From 163a910c8fb9c95925be6626edbc2ed93c4e76c3 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 27 Jan 2023 14:48:51 -0800 Subject: [PATCH 01/21] Alt generator for unique programs, WIP. We use a method to generate new programs that in general lets the program space get larger as more bits are set in the input. Should be more conducive to fuzzing. Example here generates new programs by mutating one byte of an existing unique program's seed. --- Cargo.lock | 40 ++++++++++++--- Cargo.toml | 4 ++ src/compiler/codegen.rs | 2 +- src/compiler/mod.rs | 2 + src/compiler/sexp.rs | 2 +- src/fuzzing/fuzzrng.rs | 109 ++++++++++++++++++++++++++++++++++++++++ src/fuzzing/mod.rs | 19 +++++++ src/lib.rs | 2 + 8 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 src/fuzzing/fuzzrng.rs create mode 100644 src/fuzzing/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 978665832..14f50203b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -114,6 +114,7 @@ dependencies = [ "pyo3-build-config 0.15.2", "rand", "rand_chacha", + "random_lfsr_256_galois", "serde_json", "sha2 0.9.5", "tempfile", @@ -529,9 +530,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ "unicode-ident", ] @@ -638,6 +639,19 @@ dependencies = [ "getrandom", ] +[[package]] +name = "random_lfsr_256_galois" +version = "22.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e049eaa77d779d2abb9e36bfaca1708fa3c985a796d19a160676432fcda420" +dependencies = [ + "num-traits", + "rand", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "redox_syscall" version = "0.2.13" @@ -676,9 +690,23 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "serde_json" @@ -729,9 +757,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.96" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 857cf9edf..7e2f02b13 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,11 +28,14 @@ indoc = "1.0" do-notation = "0.1.3" serde_json = "1.0" sha2 = "0.9.5" +rand = "0.8.4" tempfile = "3.3.0" clvmr = "0.1.24" binascii = "0.1.4" yaml-rust = "0.4" linked-hash-map = "0.5.6" +rand_chacha = "0.3.1" +random_lfsr_256_galois = "22.10.0" [dev-dependencies] rand = "0.8.5" @@ -44,6 +47,7 @@ crate-type = ["cdylib", "rlib"] [features] extension-module = ["pyo3"] +fuzzer = [] default = ["extension-module"] [target.'cfg(target_family="wasm")'.dependencies] diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index c81cfd826..46ea07ff3 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -113,7 +113,7 @@ fn compute_env_shape(l: Srcloc, args: Rc, helpers: &[HelperForm]) -> SExp SExp::Cons(l, Rc::new(car), cdr) } -fn create_name_lookup_( +pub fn create_name_lookup_( l: Srcloc, name: &[u8], env: Rc, diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs index 6fe0f9552..598489822 100644 --- a/src/compiler/mod.rs +++ b/src/compiler/mod.rs @@ -7,6 +7,8 @@ pub mod comptypes; pub mod debug; pub mod evaluate; pub mod frontend; +#[cfg(any(test, feature = "fuzzer"))] +pub mod fuzzer; pub mod gensym; mod inline; mod optimize; diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index d8ac5234c..a6e9bf043 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -32,7 +32,7 @@ pub enum SExp { Atom(Srcloc, Vec), } -#[cfg(test)] +#[cfg(any(test, feature = "fuzzer"))] pub fn random_atom_name(rng: &mut R, min_size: usize) -> Vec { let mut bytevec: Vec = Vec::new(); let mut len = 0; diff --git a/src/fuzzing/fuzzrng.rs b/src/fuzzing/fuzzrng.rs new file mode 100644 index 000000000..c73504dbb --- /dev/null +++ b/src/fuzzing/fuzzrng.rs @@ -0,0 +1,109 @@ +use rand::prelude::*; +use rand::Error; + +use random_lfsr_256_galois::{InitRegisterPayload, LFSRGalois, LFSRGaloisBuilder}; + +// A pseudo RNG which uses a slice for all entropy. It iterates a given slice +// many times, scrambling the bits through an LFSR in subsequent passes so that +// the fuzzer maintains a relationship between the original input bits and the +// output with some predictability. +// +// This differs from BufRng in that it's not intended to be exhaustible since +// it's being used to generate extensible data structures. +pub struct FuzzPseudoRng<'slice> { + lfsr: LFSRGalois, + slice: &'slice [u8], + + // Set on second or subsequent run + lfsr_scramble: bool, + progress: usize, +} + +impl<'slice> FuzzPseudoRng<'slice> { + pub fn new(slice: &'slice [u8]) -> Self { + // Ensure the lfsr state is consistent so the entropy bits produce + // an identical randomness every time. + let lfsr = LFSRGaloisBuilder::new() + .set_initial_payload(InitRegisterPayload::Meander) + .build(); + return FuzzPseudoRng { + lfsr: lfsr, + slice: slice, + + lfsr_scramble: false, + progress: 0, + }; + } + + fn next_u8_untreated(&mut self) -> u8 { + if self.slice.len() == 0 { + self.lfsr_scramble = true; + return 0; + } + if self.progress == self.slice.len() { + self.progress = 0; + self.lfsr_scramble = true; + } + let res = self.slice[self.progress]; + self.progress += 1; + res + } + + fn next_u32_untreated(&mut self) -> u32 { + let mut result_u32: u32 = 0; + for _ in 0..4 { + result_u32 <<= 8; + result_u32 |= self.next_u8_untreated() as u32; + } + result_u32 + } + + fn next_u64_untreated(&mut self) -> u64 { + let result_u64: u64 = self.next_u32_untreated() as u64; + result_u64 << 32 | self.next_u32_untreated() as u64 + } +} + +impl<'slice> RngCore for FuzzPseudoRng<'slice> { + #[inline(always)] + fn next_u32(&mut self) -> u32 { + if self.lfsr_scramble { + let lfsr32: u32 = self.lfsr.next(); + self.next_u32_untreated() ^ lfsr32 + } else { + self.next_u32_untreated() + } + } + + #[inline(always)] + fn next_u64(&mut self) -> u64 { + eprintln!("next_u64"); + if self.lfsr_scramble { + let lfsr64: u64 = self.lfsr.next(); + self.next_u64_untreated() ^ lfsr64 + } else { + self.next_u64_untreated() + } + } + + #[inline(always)] + fn fill_bytes(&mut self, dest: &mut [u8]) { + eprintln!("fill_bytes"); + if self.lfsr_scramble { + for i in 0..dest.len() { + let lfsr8: u8 = self.lfsr.next(); + dest[i] = self.next_u8_untreated() ^ lfsr8 + } + } else { + for i in 0..dest.len() { + dest[i] = self.next_u8_untreated() + } + } + } + + #[inline(always)] + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.fill_bytes(dest); + Ok(()) + } +} diff --git a/src/fuzzing/mod.rs b/src/fuzzing/mod.rs new file mode 100644 index 000000000..f2a942af1 --- /dev/null +++ b/src/fuzzing/mod.rs @@ -0,0 +1,19 @@ +use num_bigint::ToBigInt; +use num_traits::ToPrimitive; +use rand::prelude::*; +use rand_chacha::ChaCha8Rng; + +use crate::compiler::sexp::random_atom_name; +use crate::util::number_from_u8; + +pub mod fuzzrng; + +// Note: Used for testing out aspects of the generated programs, since i've +// funneled in the bits from fuzzing to an rng interface. +pub fn make_random_u64_seed() -> u64 { + let mut rng = ChaCha8Rng::from_entropy(); + let random_seed = random_atom_name(&mut rng, 10); + let random_seed_as_bigint = + number_from_u8(&random_seed) & 0xffffffffffff_u64.to_bigint().unwrap(); + random_seed_as_bigint.to_u64().unwrap() +} diff --git a/src/lib.rs b/src/lib.rs index 770c8b8c6..579c4c638 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,8 @@ pub mod util; pub mod classic; pub mod compiler; +#[cfg(any(test, feature="fuzzer"))] +pub mod fuzzing; // Python impl #[cfg(all(not(test), not(target_family = "wasm"), feature = "extension-module"))] From 0e64804baa42c02ead2aac6edf0a7becb5faa28a Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 27 Jan 2023 20:54:33 -0800 Subject: [PATCH 02/21] Much better diversity --- src/compiler/fuzzer.rs | 1420 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1420 insertions(+) create mode 100644 src/compiler/fuzzer.rs diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs new file mode 100644 index 000000000..f7604ef80 --- /dev/null +++ b/src/compiler/fuzzer.rs @@ -0,0 +1,1420 @@ +use num_bigint::{BigInt, ToBigInt}; +use num_traits::ToPrimitive; + +use rand::distributions::Standard; +use rand::prelude::*; +use rand::Rng; +use rand_chacha::ChaCha8Rng; +use std::borrow::Borrow; +use std::cmp::max; +use std::collections::HashSet; +use std::rc::Rc; + +use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; +use crate::compiler::clvm::truthy; +use crate::compiler::codegen::create_name_lookup_; +use crate::compiler::comptypes::{Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, LetData, LetFormKind, HelperForm}; +use crate::compiler::sexp::{enlist, SExp}; + +use crate::compiler::sexp::{random_atom_name, random_sexp}; + +use crate::classic::clvm::__type_compatibility__::{sha256, Bytes, BytesFromType, Stream}; +use crate::classic::clvm::casts::bigint_to_bytes_clvm; +use crate::compiler::runtypes::RunFailure; +use crate::compiler::sexp::decode_string; +use crate::compiler::srcloc::Srcloc; + +#[cfg(any(test, feature="fuzzer"))] +use crate::fuzzing::fuzzrng::FuzzPseudoRng; +#[cfg(any(test, feature="fuzzer"))] +use crate::fuzzing::make_random_u64_seed; + +use crate::util::{number_from_u8, Number}; + +const MIN_ARGLIST: usize = 3; +const MAX_STEPS: usize = 1000; +pub const MAX_LIST_BOUND: usize = 3; +const CURRENT_DIALECT: u32 = 21; +const BINDING_NAME_MIN: usize = 3; +const MAX_ALTERNATIVE_CPS: u16 = 5; +const MAX_FORMS_CPS: usize = 512; +const MAX_HELPER_KIND_CPS: u16 = 3; + +#[derive(Debug, Clone)] +pub struct FuzzBinding { + pub name: Vec, + pub expr: FuzzOperation, +} + +/* + * Bitstream randomness -> + * + * Our goal is to devise a format where adding one to the stream yields a + * usefully different program. + * + * That means that at the left end of the we want more consequential information + * followed by less and less consequential information. + * + * The last bits should be constants, next to last select among alternative + * objects of the same time first the program structure, then more details. + * + * It'd be nice to have the stream start with the number of objects of each + * type but that'd make simple increments make big changes. I think it's better + * to have each new object be introduced via an increment on the right most byte. + * + * So we read the data as messages, where we accept a message if its priority is + * the current or lower priority, and end if it's higher. + * + * So we must read a set of messages: + * + * Structures (helper) -> Structure (body) -> Arguments -> Selectors -> Constants + * Where Structures contains + * (Constant | Function | Macro | Main) + * (quote | arg | if | mult | sub | sha256 | let | call) + * Arguments -> (cons | @ form | atom | nil) + * Selectors -> choose nth + * Constants -> (cons | hex+ | int | nil) + * + * Each 16 bits is a message. + * + * The low 3 bits of each word defines the message type, with types 6 and 7 + * currently ignored. + * For each, the other 13 bits are taken as the payload. + */ + +#[derive(Clone, Debug, Default)] +pub struct CollectProgramStructure { + helper_structures: Vec, + body_forms: Vec, + arguments: Vec, + selectors: Vec, + constants: Vec, + main: u16 +} + +impl CollectProgramStructure { + fn get_selector(&self, sel: &mut usize) -> u16 { + if self.selectors.is_empty() { + return 0; + } + + self.selectors[*sel % self.selectors.len()] + } + + fn choose_with_default(&self, lst: &[T], choice: u16, default: T) -> T where T: Clone { + if lst.is_empty() { + return default; + } + + lst[(choice as usize) % lst.len()].clone() + } + + fn new_constant( + &self, + c: u16, + selector_choice: &mut usize, + constants: &[Rc] + ) -> Rc { + let loc = Srcloc::start("*rng*"); + let nil = Rc::new(SExp::Nil(loc.clone())); + match c & 3 { + 0 => { + Rc::new(SExp::Nil(loc.clone())) + } + 1 => { + let raw_number = c >> 2; + let bigint = + if (c & 0x2000) != 0 { + (-(c as i32)).to_bigint().unwrap() + } else { + c.to_bigint().unwrap() + }; + Rc::new(SExp::Integer(loc.clone(), bigint)) + } + 2 => { + // Hex+ + // If the last item is also a number, this number concatenates + // them. + let new_byte = ((c >> 2) & 0xff) as u8; + if !constants.is_empty() { + if let SExp::Atom(l,n) = constants[constants.len()-1].borrow() { + let mut new_atom_content = n.to_vec(); + new_atom_content.push(new_byte); + return Rc::new(SExp::Atom( + l.clone(), new_atom_content + )); + } + } + Rc::new(SExp::Atom(loc.clone(), vec![new_byte])) + } + _ => { + // Cons. + let choice_of_a = c >> 2; + let choice_of_b = self.get_selector(selector_choice); + let a = + self.choose_with_default(&constants, choice_of_a, nil.clone()); + let b = + self.choose_with_default(&constants, choice_of_b, nil.clone()); + Rc::new(SExp::Cons( + loc.clone(), a, b + )) + } + } + } + + fn new_argument( + &self, + arg: u16, + selector_choice: &mut usize, + atom_identifiers: &[Vec], + arguments: &[Rc] + ) -> Rc { + let loc = Srcloc::start("*rng*"); + let nil = Rc::new(SExp::Nil(loc.clone())); + match arg & 3 { + 0 => { + Rc::new(SExp::Nil(loc.clone())) + } + 1 => { + let letters = arguments.len(); + let letter1 = (letters % 25) as u8; + let letter2 = ((letters / 25) % 25) as u8; + let ident = vec![b'a' + letter1, b'a' + letter2]; + Rc::new(SExp::Atom( + loc.clone(), + ident + )) + } + 2 => { + // Use 1 selector, this number is for the @ binding. + let letters = arg >> 2; + let ident = atom_identifiers[letters as usize % atom_identifiers.len()].clone(); + let choice = self.get_selector(selector_choice); + let bind_also = self.choose_with_default(&arguments, choice, nil.clone()); + Rc::new(SExp::Cons( + loc.clone(), + Rc::new(SExp::atom_from_string(loc.clone(), "@")), + Rc::new(SExp::Cons( + loc.clone(), + Rc::new(SExp::Atom(loc.clone(), ident)), + Rc::new(SExp::Cons( + loc.clone(), + bind_also, + Rc::new(SExp::Nil(loc.clone())) + )) + )) + )) + } + _ => { + let choice_of_a = arg >> 2; + let choice_of_b = self.get_selector(selector_choice); + let a = + self.choose_with_default(&arguments, choice_of_a, nil.clone()); + let b = + self.choose_with_default(&arguments, choice_of_b, nil.clone()); + Rc::new(SExp::Cons( + loc.clone(), a, b + )) + } + } + } + + fn isolate_arg_sites( + &self, + arg_sites: &mut Vec>, + args: Rc, + ) { + if let SExp::Cons(_, f, r) = args.borrow() { + arg_sites.push(f.clone()); + self.isolate_arg_sites(arg_sites, r.clone()); + } else { + arg_sites.push(args.clone()); + } + } + + fn new_bodyform( + &self, + b: u16, + selector_choice: &mut usize, + atom_identifiers: &[Vec], + constants: &[Rc], + arguments: &[Rc], + body_forms: &[Rc] + ) -> Rc { + let loc = Srcloc::start("*rng*"); + let nil = Rc::new(SExp::Nil(loc.clone())); + let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); + + // (quote | arg | if | mult | sub | sha256 | let | call) + match b & 7 { + 0 => { + let choice_of_const = b >> 3; + let constant = self.choose_with_default(&constants, choice_of_const, nil.clone()); + let constant_borrowed: &SExp = constant.borrow(); + Rc::new(BodyForm::Quoted(constant_borrowed.clone())) + } + 1 => { + let choice_of_arg = b >> 3; + let arg = self.choose_with_default(&atom_identifiers, choice_of_arg, vec![b'X']); + Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), arg))) + } + 2 => { + let choice_of_cond = b >> 3; + let choice_of_then = self.get_selector(selector_choice); + let choice_of_else = self.get_selector(selector_choice); + let use_cond = + self.choose_with_default(&body_forms, choice_of_cond, body_nil.clone()); + let use_then = + self.choose_with_default(&body_forms, choice_of_then, body_nil.clone()); + let use_else = + self.choose_with_default(&body_forms, choice_of_else, body_nil.clone()); + Rc::new(BodyForm::Call( + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), "if"))), + use_cond, + use_then, + use_else + ] + )) + } + 3 => { + let choice_of_a = b >> 3; + let choice_of_b = self.get_selector(selector_choice); + let use_a = + self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); + let use_b = + self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); + Rc::new(BodyForm::Call( + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![18]))), + use_a, + use_b + ] + )) + } + 4 => { + let choice_of_a = b >> 3; + let choice_of_b = self.get_selector(selector_choice); + let use_a = + self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); + let use_b = + self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); + Rc::new(BodyForm::Call( + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![17]))), + use_a, + use_b + ] + )) + } + 5 => { + let choice_of_a = b >> 3; + let choice_of_b = self.get_selector(selector_choice); + let use_a = + self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); + let use_b = + self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); + Rc::new(BodyForm::Call( + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![11]))), + use_a, + use_b + ] + )) + } + 6 => { + // Synthesize a let form. + let num_bindings = (b >> 3) & 3; + let kind = + if (b >> 5) != 0 { + LetFormKind::Parallel + } else { + LetFormKind::Sequential + }; + let mut collected_names = Vec::new(); + let mut collected_bindings = Vec::new(); + for i in 0..=num_bindings { + let choice_of_name = + self.get_selector(selector_choice); + let choice_of_body = b >> 6; + let arg_atom = + atom_identifiers[choice_of_name as usize % atom_identifiers.len()].clone(); + if collected_names.contains(&arg_atom) { + break; + } + + let body = + self.choose_with_default(&body_forms, choice_of_body, body_nil.clone()); + + collected_names.push(arg_atom.clone()); + collected_bindings.push(Rc::new(Binding { + loc: loc.clone(), + nl: loc.clone(), + name: arg_atom, + body: body + })); + } + + let body = + self.choose_with_default(&body_forms, b >> 5, body_nil.clone()); + + Rc::new(BodyForm::Let( + kind, + LetData { + loc: loc.clone(), + kw: None, + bindings: collected_bindings, + body: body + } + )) + } + _ => { + // Call + if self.helper_structures.is_empty() { + return body_nil.clone(); + } + + let choice_of_helper = (b >> 3) as usize % self.helper_structures.len(); + let helper_spec = + self.helper_structures[choice_of_helper as usize % self.helper_structures.len()]; + let choice_of_arg = helper_spec >> 3; + let call_args = + self.choose_with_default(&arguments, choice_of_arg, nil.clone()); + let mut arg_sites = Vec::new(); + self.isolate_arg_sites(&mut arg_sites, call_args); + let helper_name = format!("helper_{}", choice_of_helper); + if helper_spec & 3 == 0 { + // Reference constant + return Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), &helper_name))); + } + + // Reference callable + let mut call_args: Vec> = + arg_sites.iter().map(|site| { + let choice_of_expr = + self.get_selector(selector_choice); + self.choose_with_default(&body_forms, choice_of_expr, body_nil.clone()) + }).collect(); + call_args.insert(0, Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), &helper_name)))); + Rc::new(BodyForm::Call( + loc.clone(), + call_args + )) + } + } + } + + fn new_helper( + &self, + i: usize, + h: u16, + selector_choice: &mut usize, + constants: &[Rc], + arguments: &[Rc], + body_forms: &[Rc], + helper_forms: &[HelperForm] + ) -> HelperForm { + let loc = Srcloc::start("*rng*"); + let nil = Rc::new(SExp::Nil(loc.clone())); + let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); + + let is_inline = ((h >> 2) & 1) == 1; + let choice_of_args = h >> 3; + let choice_of_body = self.get_selector(selector_choice); + let arguments = + self.choose_with_default(&arguments, choice_of_args, nil.clone()); + let body = + self.choose_with_default(&body_forms, choice_of_body, body_nil.clone()); + let helper_name = format!("helper_{}", i).as_bytes().to_vec(); + match h & 3 { + 0 => { + HelperForm::Defconstant(DefconstData { + loc: loc.clone(), + name: helper_name, + kw: None, + nl: loc.clone(), + body: body + }) + } + 1 => { + HelperForm::Defun(is_inline, DefunData { + loc: loc.clone(), + name: helper_name, + kw: None, + nl: loc.clone(), + args: arguments, + body + }) + } + _ => { + let program = CompileForm { + loc: loc.clone(), + include_forms: Vec::new(), + args: arguments.clone(), + helpers: helper_forms.to_vec(), + exp: body + }; + HelperForm::Defmacro(DefmacData { + loc: loc.clone(), + name: helper_name, + kw: None, + nl: loc.clone(), + args: arguments, + program: Rc::new(program) + }) + } + + } + } + + fn to_program(&self) -> CompileForm { + // Build constants... + let loc = Srcloc::start("*rng*"); + let mut selector_choice = 0; + let nil = Rc::new(SExp::Nil(loc.clone())); + let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); + + let mut constants = Vec::new(); + for c in self.constants.iter() { + let new_const = self.new_constant(*c, &mut selector_choice, &constants); + constants.push(new_const); + } + + let mut arguments = Vec::new(); + let mut atom_identifiers = vec![b"X".to_vec()]; + + for arg in self.arguments.iter() { + let new_arg = self.new_argument( + *arg, + &mut selector_choice, + &atom_identifiers, + &arguments + ); + if let SExp::Atom(_,n) = new_arg.borrow() { + atom_identifiers.push(n.clone()); + } + arguments.push(new_arg); + } + + let mut body_forms = Vec::new(); + + for b in self.body_forms.iter() { + let new_form = self.new_bodyform( + *b, + &mut selector_choice, + &atom_identifiers, + &constants, + &arguments, + &body_forms + ); + body_forms.push(new_form); + } + + let mut helper_forms = Vec::new(); + for (i,h) in self.helper_structures.iter().enumerate() { + let new_helper = self.new_helper( + i, + *h, + &mut selector_choice, + &constants, + &arguments, + &body_forms, + &helper_forms + ); + helper_forms.push(new_helper); + } + + let body = self.new_bodyform( + self.main, + &mut selector_choice, + &atom_identifiers, + &constants, + &arguments, + &body_forms + ); + let use_arguments = self.get_selector(&mut selector_choice); + let arguments = + self.choose_with_default(&arguments, use_arguments, nil.clone()); + + CompileForm { + loc: loc.clone(), + include_forms: Vec::new(), + args: arguments, + helpers: helper_forms, + exp: body + } + } +} + +impl Distribution for Standard { + fn sample(&self, rng: &mut R) -> CollectProgramStructure { + let mut message_kind: u16 = MAX_ALTERNATIVE_CPS; + let mut helper_kind: u16 = MAX_HELPER_KIND_CPS; + let mut iters = 0; + let mut cps: CollectProgramStructure = Default::default(); + let mut have_body = false; + loop { + let mut input: u16 = rng.gen(); + let input_type = input & 7; + let input_val = input >> 3; + let mut have_body = false; + + iters += 1; + if iters > MAX_FORMS_CPS { + break; + } + + // Stop if out of range. + if input_type > MAX_ALTERNATIVE_CPS { + break; + } + + // Stop if we get a retrograde message. + if input_type > message_kind { + break; + } + + // A new message type advances out of the prev phase. + message_kind = input; + match input_type { + 4 => { + let new_helper_kind = input_val & 3; + if new_helper_kind > MAX_HELPER_KIND_CPS { + message_kind += 1; + continue; + } + + if new_helper_kind > helper_kind { + message_kind += 1; + continue; + } + + if new_helper_kind == 0 { + have_body = true; + cps.main = input_val; + message_kind += 1; + continue; + } + + cps.helper_structures.push(input_val); + } + 3 => cps.body_forms.push(input_val), + 2 => cps.arguments.push(input_val), + 1 => cps.selectors.push(input_val), + 0 => cps.constants.push(input_val), + _ => { } + } + } + + if !have_body { + // Populate with call to 0th function. + cps.main = 7; + } + + cps + } +} + +#[test] +fn test_make_program_structure_1() { + let mut fpr = FuzzPseudoRng::new(&[0,0,0,12,0,0,0,3,0,0,0,2,0,0,0,1,0,0,0,0]); + let cps: CollectProgramStructure = fpr.gen(); + let zero_u16: &[u16] = &[0]; + let one_u16: &[u16] = &[1]; + assert_eq!(&cps.helper_structures, one_u16); + assert_eq!(&cps.body_forms, zero_u16); + assert_eq!(&cps.arguments, zero_u16); + assert_eq!(&cps.selectors, zero_u16); + assert_eq!(&cps.constants, zero_u16); +} + +fn do_program(programs: &mut Vec>, unique: &mut HashSet, buf: &[u8]) { + let mut fpr = FuzzPseudoRng::new(&buf); + let cps: CollectProgramStructure = fpr.gen(); + let program = cps.to_program(); + let pts = program.to_sexp().to_string(); + if !unique.contains(&pts) { + eprintln!("{}", pts); + programs.push(buf.to_vec()); + unique.insert(pts); + } +} + +#[test] +fn test_make_program_structure_2() { + let mut rng = ChaCha8Rng::seed_from_u64(make_random_u64_seed()); + let mut buf = &[0,0,0,0]; + let this_len = buf.len(); + let mut programs = Vec::new(); + let mut unique = HashSet::new(); + do_program(&mut programs, &mut unique, buf); + for p in 0..50000 { + let choice = rng.gen_range(0..programs.len()); + let mut this_buf = programs[choice].to_vec(); + let mut next_byte = rng.gen_range(0..=buf.len()); + if next_byte == buf.len() { + this_buf.push(rng.gen()); + } else { + let next_bit = rng.gen_range(0..8); + this_buf[next_byte % this_len] ^= rng.gen::(); + } + do_program(&mut programs, &mut unique, &this_buf); + } + todo!(); +} + +// We don't actually need all operators here, just a good selection with +// semantics that are distinguishable. +#[derive(Debug, Clone)] +pub enum FuzzOperation { + Argref(usize), + Quote(SExp), + If(Rc, Rc, Rc), + Multiply(Rc, Rc), + Sub(Rc, Rc), + Sha256(Vec), + Let(Vec, Rc), + Call(u8, Vec), +} + +#[derive(Debug, Clone)] +pub enum ArgListType { + ProperList(u8), + Structure(SExp), +} + +#[derive(Debug, Clone)] +pub struct FuzzFunction { + pub inline: bool, + pub number: u8, + pub args: ArgListType, + pub body: FuzzOperation, +} + +#[derive(Debug, Clone)] +pub struct FuzzProgram { + pub args: ArgListType, + pub functions: Vec, + pub body: FuzzOperation, +} + +#[derive(Debug, Clone)] +pub struct FuzzOldProgram { + pub program: FuzzProgram, +} + +fn atom_list(sexp: &SExp) -> Vec> { + match sexp { + SExp::Nil(_) => vec![], + SExp::Atom(_, v) => { + if v.is_empty() { + vec![] + } else { + vec![v.clone()] + } + } + SExp::QuotedString(_, _, _) => vec![], + SExp::Integer(_, _) => vec![], + SExp::Cons(_, a, b) => { + let mut a_vec = atom_list(a.borrow()); + let b_vec = atom_list(b.borrow()); + for b_item in b_vec.iter() { + a_vec.push(b_item.clone()); + } + a_vec + } + } +} + +fn select_argument( + num: usize, + fun: &FuzzProgram, + bindings: &[Vec], +) -> (SExp, Option) { + let args_sexp = fun.args.to_sexp(); + let select_group = (num >> 8) % (bindings.len() + 1); + if select_group == bindings.len() { + // Select from arguments + let arg_list = atom_list(&args_sexp); + let nil = SExp::Nil(args_sexp.loc()); + if arg_list.is_empty() { + (nil.clone(), Some(FuzzOperation::Quote(nil))) + } else { + let selected_arg = arg_list[num & 0xff % arg_list.len()].clone(); + (SExp::Atom(args_sexp.loc(), selected_arg), None) + } + } else { + // Select a binding group using the second byte, + let group = &bindings[select_group]; + let select_binding = (num & 0xff) % group.len(); + let selected_binding = &group[select_binding]; + // Select a binding using the first byte. + ( + SExp::Atom(args_sexp.loc(), selected_binding.name.clone()), + Some(selected_binding.expr.clone()), + ) + } +} + +fn select_call(num: u8, prog: &FuzzProgram) -> (String, FuzzFunction) { + if prog.functions.len() == 0 { + panic!("we make programs with at least one function"); + } + let selected_num = num % prog.functions.len() as u8; + let selected = &prog.functions[selected_num as usize]; + (format!("fun_{}", selected_num), selected.clone()) +} + +fn make_operator(op: String, args: Vec) -> SExp { + let loc = Srcloc::start(&"*rng*".to_string()); + let mut result = SExp::Nil(loc.clone()); + + for i_reverse in 0..args.len() { + let i = args.len() - i_reverse - 1; + result = SExp::Cons(loc.clone(), Rc::new(args[i].clone()), Rc::new(result)); + } + + SExp::Cons( + loc.clone(), + Rc::new(SExp::atom_from_string(loc.clone(), &op)), + Rc::new(result), + ) +} + +fn distribute_args( + a: ArgListType, + fun: &FuzzProgram, + bindings: &[Vec], + arginputs: &Vec, + spine: bool, + argn: u8, +) -> (u8, SExp) { + let loc = Srcloc::start(&"*rng*".to_string()); + match a { + ArgListType::ProperList(0) => (argn, SExp::Nil(loc.clone())), + ArgListType::ProperList(n) => { + let rest_result = distribute_args( + ArgListType::ProperList(n - 1), + fun, + bindings, + arginputs, + spine, + argn + 1, + ); + ( + rest_result.0, + SExp::Cons( + loc.clone(), + Rc::new(arginputs[argn as usize].clone()), + Rc::new(rest_result.1), + ), + ) + } + ArgListType::Structure(SExp::Nil(l)) => (argn, SExp::Nil(l.clone())), + ArgListType::Structure(SExp::Cons(l, a, b)) => { + let a_borrow: &SExp = a.borrow(); + let b_borrow: &SExp = b.borrow(); + let first_res = distribute_args( + ArgListType::Structure(a_borrow.clone()), + fun, + bindings, + arginputs, + false, + argn, + ); + let rest_res = distribute_args( + ArgListType::Structure(b_borrow.clone()), + fun, + bindings, + arginputs, + spine, + argn + first_res.0, + ); + let res = if spine { + SExp::Cons(l.clone(), Rc::new(first_res.1), Rc::new(rest_res.1)) + } else { + make_operator("c".to_string(), vec![first_res.1, rest_res.1]) + }; + (rest_res.0, res) + } + ArgListType::Structure(_) => { + if spine { + distribute_args( + ArgListType::ProperList(1), + fun, + bindings, + arginputs, + spine, + argn, + ) + } else { + (argn + 1_u8, arginputs[argn as usize].clone()) + } + } + } +} + +fn random_args(rng: &mut R, loc: Srcloc, a: ArgListType) -> SExp { + match a { + ArgListType::ProperList(0) => SExp::Nil(loc.clone()), + ArgListType::ProperList(n) => { + let loc = Srcloc::start("*rng*"); + enlist(loc, (0..n).map(|_| Rc::new(rng.gen())).collect()) + } + ArgListType::Structure(SExp::Nil(l)) => SExp::Nil(l.clone()), + ArgListType::Structure(SExp::Cons(_, a, b)) => { + let borrowed_a: &SExp = a.borrow(); + let borrowed_b: &SExp = b.borrow(); + SExp::Cons( + loc.clone(), + Rc::new(random_args( + rng, + loc.clone(), + ArgListType::Structure(borrowed_a.clone()), + )), + Rc::new(random_args( + rng, + loc.clone(), + ArgListType::Structure(borrowed_b.clone()), + )), + ) + } + ArgListType::Structure(_) => { + let random_64: u64 = rng.gen(); + SExp::Integer(loc.clone(), random_64.to_bigint().unwrap()) + } + } +} + +impl FuzzOperation { + pub fn to_sexp(&self, fun: &FuzzProgram, bindings: &[Vec]) -> SExp { + let loc = Srcloc::start(&"*rng*".to_string()); + match self { + FuzzOperation::Argref(argument_num) => { + let argument = select_argument(*argument_num as usize, fun, &bindings); + argument.0 + } + FuzzOperation::Quote(s) => SExp::Cons( + loc.clone(), + Rc::new(SExp::atom_from_string(loc.clone(), &"q".to_string())), + Rc::new(s.clone()), + ), + FuzzOperation::If(cond, ct, cf) => make_operator( + "if".to_string(), + vec![ + cond.to_sexp(fun, bindings), + ct.to_sexp(fun, bindings), + cf.to_sexp(fun, bindings), + ], + ), + FuzzOperation::Multiply(a, b) => make_operator( + "*".to_string(), + vec![a.to_sexp(fun, bindings), b.to_sexp(fun, bindings)], + ), + FuzzOperation::Sub(a, b) => make_operator( + "-".to_string(), + vec![a.to_sexp(fun, bindings), b.to_sexp(fun, bindings)], + ), + FuzzOperation::Sha256(ents) => make_operator( + "sha256".to_string(), + ents.iter().map(|x| x.to_sexp(fun, bindings)).collect(), + ), + FuzzOperation::Let(our_bindings, body) => { + let loc = Srcloc::start(&"*rng*".to_string()); + let mut bindings_done = SExp::Nil(loc.clone()); + + for b in our_bindings.iter().rev() { + bindings_done = SExp::Cons( + loc.clone(), + Rc::new(SExp::Cons( + loc.clone(), + Rc::new(SExp::Atom(loc.clone(), b.name.clone())), + Rc::new(SExp::Cons( + loc.clone(), + Rc::new(b.expr.to_sexp(fun, bindings)), + Rc::new(SExp::Nil(loc.clone())), + )), + )), + Rc::new(bindings_done), + ); + } + + let mut inner_bindings = bindings.to_vec(); + inner_bindings.push(our_bindings.clone()); + + make_operator( + "let".to_string(), + vec![bindings_done, body.to_sexp(fun, &inner_bindings)], + ) + } + FuzzOperation::Call(selection, args) => { + let loc = Srcloc::start(&"*rng*".to_string()); + let called_fun = select_call(*selection, fun); + let mut reified_args = Vec::new(); + for a in args.iter() { + reified_args.push(a.to_sexp(fun, bindings)); + } + let args = distribute_args( + called_fun.1.args.clone(), + fun, + bindings, + &reified_args, + true, + 0, + ); + SExp::Cons( + loc.clone(), + Rc::new(SExp::atom_from_string(loc.clone(), &called_fun.0)), + Rc::new(args.1), + ) + } + } + } +} + +fn make_random_call(rng: &mut R, dialect: u32, remaining: usize) -> FuzzOperation { + FuzzOperation::Call( + rng.gen(), + (0..=255) + .map(|_| random_operation(rng, dialect, remaining - 1)) + .collect(), + ) +} + +// FuzzOperation is potentially infinite so we'll limit the depth to something +// sensible. +fn random_operation(rng: &mut R, dialect: u32, remaining: usize) -> FuzzOperation { + if remaining < 2 { + FuzzOperation::Quote(random_sexp(rng, remaining)) + } else { + let op_bound = if dialect >= 21 { 7 } else { 6 }; + let alternative: usize = rng.gen_range(0..=op_bound); + match alternative { + 0 => FuzzOperation::Argref(rng.gen()), + 1 => FuzzOperation::If( + Rc::new(random_operation(rng, dialect, remaining - 1)), + Rc::new(random_operation(rng, dialect, remaining - 1)), + Rc::new(random_operation(rng, dialect, remaining - 1)), + ), + 2 => FuzzOperation::Multiply( + Rc::new(random_operation(rng, dialect, remaining - 1)), + Rc::new(random_operation(rng, dialect, remaining - 1)), + ), + 3 => FuzzOperation::Sub( + Rc::new(random_operation(rng, dialect, remaining - 1)), + Rc::new(random_operation(rng, dialect, remaining - 1)), + ), + 4 => { + let bound: usize = rng.gen_range(0..=MAX_LIST_BOUND); + FuzzOperation::Sha256( + (0..=bound) + .map(|_| random_operation(rng, dialect, remaining - 1)) + .collect(), + ) + } + 5 => make_random_call(rng, dialect, remaining - 1), + 6 => FuzzOperation::Quote(random_sexp(rng, remaining)), + _ => { + let bound: usize = rng.gen_range(1..=5); + let new_bindings: Vec = (1..=bound) + .map(|_| FuzzBinding { + name: random_atom_name(rng, BINDING_NAME_MIN), + expr: random_operation(rng, dialect, remaining - 1), + }) + .collect(); + FuzzOperation::Let( + new_bindings, + Rc::new(random_operation(rng, dialect, remaining - 1)), + ) + } + } + } +} + +impl Distribution for Standard { + fn sample(&self, rng: &mut R) -> FuzzOperation { + random_operation(rng, 22, MAX_LIST_BOUND) + } +} + +fn min_arglist(remaining: usize) -> usize { + max(remaining, MIN_ARGLIST) +} + +fn random_arglist_cons(rng: &mut R, loc: &Srcloc, remaining: usize) -> SExp { + if rng.gen() || remaining < 1 { + SExp::Atom(loc.clone(), random_atom_name(rng, 2)) + } else { + let left = random_arglist_cons(rng, loc, remaining - 1); + let right = random_arglist_cons(rng, loc, remaining - 1); + SExp::Cons(loc.clone(), Rc::new(left), Rc::new(right)) + } +} + +fn random_arglist(rng: &mut R, remaining: usize) -> ArgListType { + let loc = Srcloc::start("*arglist*"); + let truncated_len = (remaining % 255) as u8; + if rng.gen() { + ArgListType::ProperList(rng.gen_range(0..=truncated_len)) + } else { + let mut structure = SExp::Nil(loc.clone()); + for _ in 0..=min_arglist(truncated_len as usize) { + structure = SExp::Cons( + loc.clone(), + Rc::new(random_arglist_cons(rng, &loc, remaining - 1)), + Rc::new(structure), + ); + } + + ArgListType::Structure(structure) + } +} + +impl Distribution for Standard { + fn sample(&self, rng: &mut R) -> ArgListType { + random_arglist(rng, MAX_LIST_BOUND) + } +} + +impl ArgListType { + pub fn random_args(&self, rng: &mut R) -> SExp { + let loc = Srcloc::start(&"*rng*".to_string()); + match self { + ArgListType::ProperList(n) => { + let mut args = SExp::Nil(loc.clone()); + for _ in 0..*n { + let random_bytes: Vec = (0..=MAX_LIST_BOUND).map(|_| rng.gen()).collect(); + args = SExp::Cons( + args.loc(), + Rc::new(SExp::atom_from_vec(loc.clone(), &random_bytes)), + Rc::new(args.clone()), + ); + } + args + } + ArgListType::Structure(SExp::Nil(l)) => SExp::Nil(l.clone()), + ArgListType::Structure(SExp::Cons(l, a, b)) => { + let aborrow: &SExp = a.borrow(); + let bborrow: &SExp = b.borrow(); + let aclone = aborrow.clone(); + let bclone = bborrow.clone(); + let arg_a = ArgListType::Structure(aclone).random_args(rng); + let arg_b = ArgListType::Structure(bclone).random_args(rng); + SExp::Cons(l.clone(), Rc::new(arg_a), Rc::new(arg_b)) + } + ArgListType::Structure(_) => rng.gen(), + } + } + + fn to_sexp(&self) -> SExp { + let loc = Srcloc::start(&"*rng*".to_string()); + match self { + ArgListType::ProperList(n) => { + let mut args = SExp::Nil(loc.clone()); + for i_reverse in 0..*n { + let i = n - i_reverse; + args = SExp::Cons( + args.loc(), + Rc::new(SExp::atom_from_string(loc.clone(), &format!("arg_{}", i))), + Rc::new(args.clone()), + ); + } + args + } + ArgListType::Structure(s) => s.clone(), + } + } +} + +fn random_function(rng: &mut R, dialect: u32, remaining: usize) -> FuzzFunction { + FuzzFunction { + inline: rng.gen(), + number: 0, + args: random_arglist(rng, remaining - 1), + body: random_operation(rng, dialect, remaining - 1), + } +} + +impl Distribution for Standard { + fn sample(&self, rng: &mut R) -> FuzzFunction { + random_function(rng, CURRENT_DIALECT, MAX_LIST_BOUND) + } +} + +impl FuzzFunction { + fn to_sexp(&self, fun: &FuzzProgram) -> SExp { + let fuzzloc = Srcloc::start(&"*fuzz*".to_string()); + let initial_atom = if self.inline { + SExp::atom_from_string(fuzzloc.clone(), &"defun-inline".to_string()) + } else { + SExp::atom_from_string(fuzzloc.clone(), &"defun".to_string()) + }; + let name_atom = SExp::atom_from_string(fuzzloc.clone(), &format!("fun_{}", self.number)); + let args_sexp = self.args.to_sexp(); + let body_sexp = self.body.to_sexp(&self.to_program(fun), &Vec::new()); + SExp::Cons( + fuzzloc.clone(), + Rc::new(initial_atom), + Rc::new(SExp::Cons( + fuzzloc.clone(), + Rc::new(name_atom), + Rc::new(SExp::Cons( + fuzzloc.clone(), + Rc::new(args_sexp), + Rc::new(SExp::Cons( + fuzzloc.clone(), + Rc::new(body_sexp), + Rc::new(SExp::Nil(fuzzloc.clone())), + )), + )), + )), + ) + } + + fn to_program(&self, parent: &FuzzProgram) -> FuzzProgram { + FuzzProgram { + args: self.args.clone(), + functions: parent.functions.clone(), + body: self.body.clone(), + } + } +} + +/* + * Produce chialisp frontend code with an expected result + */ +fn random_program(rng: &mut R, dialect: u32, remaining: usize) -> FuzzProgram { + let num_funs = rng.gen_range(1..=MAX_LIST_BOUND); + let funs: Vec = (1..=num_funs) + .map(|_| random_function(rng, dialect, remaining - 1)) + .enumerate() + .map(|(i, f): (usize, FuzzFunction)| { + let mut fcopy = f.clone(); + fcopy.number = i as u8; + fcopy + }) + .collect(); + FuzzProgram { + args: random_arglist(rng, remaining), + functions: funs, + body: random_operation(rng, dialect, remaining), + } +} + +impl Distribution for Standard { + fn sample(&self, rng: &mut R) -> FuzzProgram { + random_program(rng, CURRENT_DIALECT, MAX_LIST_BOUND) + } +} + +fn evaluate_to_numbers( + prog: &FuzzProgram, + args: &SExp, + bindings: &[Vec], + a: &FuzzOperation, + b: &FuzzOperation, + steps: usize, +) -> Result<(BigInt, BigInt), RunFailure> { + let a_val = interpret_program(prog, args, bindings, a, steps - 1)?; + let b_val = interpret_program(prog, args, bindings, b, steps - 1)?; + match (&a_val, &b_val) { + (SExp::Integer(_, a), SExp::Integer(_, b)) => Ok((a.clone(), b.clone())), + (SExp::Cons(l, _, _), _) => Err(RunFailure::RunErr( + l.clone(), + format!("*: expected atom got {}", a_val.to_string()), + )), + (_, SExp::Cons(l, _, _)) => Err(RunFailure::RunErr( + l.clone(), + format!("*: expected atom got {}", b_val.to_string()), + )), + (a, b) => { + let num_a = a + .get_number() + .map_err(|e| RunFailure::RunErr(a.loc(), e.1))?; + let num_b = b + .get_number() + .map_err(|e| RunFailure::RunErr(b.loc(), e.1))?; + Ok((num_a, num_b)) + } + } +} + +fn byte_vec_of_sexp(val: &SExp) -> Result, RunFailure> { + match val { + SExp::Nil(_) => Ok(Vec::new()), + SExp::Atom(_, a) => Ok(a.clone()), + SExp::QuotedString(_, _, s) => Ok(s.clone()), + SExp::Integer(_, i) => Ok(bigint_to_bytes_clvm(i).data().clone()), + _ => Err(RunFailure::RunErr( + val.loc(), + format!("attempt to convert {} to bytes", val.to_string()), + )), + } +} + +fn choose_path(path: Number, args: Rc) -> Result, RunFailure> { + if path == bi_one() { + Ok(args) + } else { + match args.borrow() { + SExp::Cons(_, a, b) => { + let odd = bi_one() & path.clone(); + if odd != bi_zero() { + choose_path(path >> 1, b.clone()) + } else { + choose_path(path >> 1, a.clone()) + } + } + _ => Err(RunFailure::RunErr(args.loc(), "path into atom".to_string())), + } + } +} + +fn interpret_program( + prog: &FuzzProgram, + args: &SExp, + bindings: &[Vec], + expr: &FuzzOperation, + steps: usize, +) -> Result { + if steps < 1 { + return Err(RunFailure::RunErr( + args.loc(), + "too many steps taken".to_string(), + )); + } + let loc = Srcloc::start(&"*interp*".to_string()); + match &expr { + FuzzOperation::Argref(n) => { + let (argname, run_expression) = select_argument(*n as usize, prog, bindings); + if let Some(to_run) = run_expression { + // Run binding code selected. + interpret_program(prog, args, bindings, &to_run, steps - 1) + } else { + // Select argument from env. + let argpath = create_name_lookup_( + args.loc(), + &argname.to_string().as_bytes(), + Rc::new(prog.args.to_sexp()), + Rc::new(prog.args.to_sexp()), + ) + .map_err(|e| RunFailure::RunErr(e.0.clone(), e.1.clone()))?; + let argval = choose_path(argpath.to_bigint().unwrap(), Rc::new(args.clone()))?; + let argval_borrow: &SExp = argval.borrow(); + interpret_program( + prog, + args, + bindings, + &FuzzOperation::Quote(argval_borrow.clone()), + steps - 1, + ) + } + } + FuzzOperation::Quote(exp) => Ok(exp.clone()), + FuzzOperation::If(cond, iftrue, iffalse) => { + let borrowed_cond: &FuzzOperation = cond.borrow(); + interpret_program(prog, args, bindings, borrowed_cond, steps - 1) + .map(|cond_res| truthy(Rc::new(cond_res))) + .and_then(|cond_res| { + if cond_res { + let borrowed_iftrue: &FuzzOperation = iftrue.borrow(); + interpret_program(prog, args, bindings, borrowed_iftrue, steps - 1) + } else { + let borrowed_iffalse: &FuzzOperation = iffalse.borrow(); + interpret_program(prog, args, bindings, borrowed_iffalse, steps - 1) + } + }) + } + FuzzOperation::Multiply(a, b) => { + let (a_val, b_val) = + evaluate_to_numbers(prog, args, bindings, a.borrow(), b.borrow(), steps - 1)?; + Ok(SExp::Integer(loc, a_val * b_val)) + } + FuzzOperation::Sub(a, b) => { + let (a_val, b_val) = + evaluate_to_numbers(prog, args, bindings, a.borrow(), b.borrow(), steps - 1)?; + Ok(SExp::Integer(loc, a_val - b_val)) + } + FuzzOperation::Sha256(lst) => { + let loc = Srcloc::start(&"*sha256*".to_string()); + let mut bytes_stream = Stream::new(None); + for elt in lst.iter() { + let output = interpret_program(prog, args, bindings, &elt, steps - 1)?; + let output_bytes = byte_vec_of_sexp(&output)?; + bytes_stream.write(Bytes::new(Some(BytesFromType::Raw(output_bytes)))); + } + Ok(SExp::Atom( + loc, + sha256(bytes_stream.get_value()).data().clone(), + )) + } + FuzzOperation::Let(new_bindings, body) => { + let mut total_bindings = bindings.to_vec(); + total_bindings.push(new_bindings.clone()); + interpret_program(prog, args, &total_bindings, body.borrow(), steps - 1) + } + FuzzOperation::Call(fun, call_args) => { + let called_fun = select_call(*fun, prog); + let mut reified_args = Vec::new(); + + // Interpret all arguments. + for a in call_args.iter() { + reified_args.push(interpret_program(prog, args, bindings, a, steps - 1)?); + } + + // Use reified arguments since we're assuming they're sexp. + let distributed_args = distribute_args( + called_fun.1.args.clone(), + prog, + bindings, + &reified_args, + true, + 0, + ); + interpret_program( + &called_fun.1.to_program(prog), + &distributed_args.1, + &Vec::new(), + &called_fun.1.body.clone(), + steps - 1, + ) + } + } +} + +impl FuzzProgram { + pub fn to_sexp(&self) -> SExp { + let mut body_vec = Vec::new(); + body_vec.push(self.args.to_sexp()); + for f in &self.functions { + body_vec.push(f.to_sexp(self)) + } + body_vec.push(self.body.to_sexp(self, &Vec::new())); + make_operator("mod".to_string(), body_vec) + } + + pub fn random_args(&self, rng: &mut R) -> SExp { + let srcloc = Srcloc::start(&"*args*".to_string()); + random_args(rng, srcloc, self.args.clone()) + } + + pub fn interpret(&self, args: SExp) -> Result { + interpret_program(self, &args, &Vec::new(), &self.body, MAX_STEPS) + } +} + +fn random_old_program(rng: &mut R, remaining: usize) -> FuzzOldProgram { + FuzzOldProgram { + program: random_program(rng, 0, remaining), + } +} + +impl Distribution for Standard { + fn sample(&self, rng: &mut R) -> FuzzOldProgram { + random_old_program(rng, MAX_LIST_BOUND) + } +} From 6b97abd841314da2e0f2022327480af8f90c130b Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 30 Jan 2023 15:40:06 -0800 Subject: [PATCH 03/21] Better program generation --- Cargo.toml | 5 + src/compiler/fuzzer.rs | 384 +++++++++++++++++++++++++---------------- src/compiler/sexp.rs | 12 +- src/fuzzing/fuzzrng.rs | 46 +---- src/lib.rs | 2 + 5 files changed, 252 insertions(+), 197 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7e2f02b13..5c0deb8b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -90,3 +90,8 @@ path = "src/classic/bins/shrink.rs" [[bin]] name = "repl" path = "src/classic/bins/repl.rs" + +[[bin]] +name = "chia_prog_gen" +path = "src/classic/bins/chia_prog_gen.rs" +default-features = ["fuzzer"] \ No newline at end of file diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index f7604ef80..89ae39d05 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -89,18 +89,118 @@ pub struct CollectProgramStructure { arguments: Vec, selectors: Vec, constants: Vec, + choice: usize, main: u16 } -impl CollectProgramStructure { - fn get_selector(&self, sel: &mut usize) -> u16 { - if self.selectors.is_empty() { - return 0; +fn arg_identifiers( + in_scope: &mut Vec>, + args: Rc +) { + match args.borrow() { + SExp::Cons(_,a,b) => { + arg_identifiers(in_scope, a.clone()); + arg_identifiers(in_scope, b.clone()); + } + SExp::Atom(_,n) => { + if n != b"@" { + in_scope.push(n.clone()); + } } + _ => { } + } +} + +fn rewrite_identifiers_bodyform( + in_scope: &Vec>, + body_form: &BodyForm +) -> BodyForm { + match body_form { + BodyForm::Let(LetFormKind::Sequential, data) => { + let mut newly_bound = in_scope.clone(); + let mut new_bindings = Vec::new(); + for b in data.bindings.iter() { + let new_binding_body = rewrite_identifiers_bodyform( + &newly_bound, + b.body.borrow() + ); + newly_bound.push(b.name.clone()); + } + let mut new_data = data.clone(); + new_data.bindings = new_bindings; + + let new_body = rewrite_identifiers_bodyform( + &newly_bound, data.body.borrow() + ); + new_data.body = Rc::new(new_body); - self.selectors[*sel % self.selectors.len()] + BodyForm::Let(LetFormKind::Sequential, new_data) + } + BodyForm::Let(LetFormKind::Parallel, data) => { + let new_bindings: Vec> = data.bindings.iter().map(|b| { + let mut b_borrowed: &Binding = b.borrow(); + let mut b_clone = b_borrowed.clone(); + b_clone.body = Rc::new(rewrite_identifiers_bodyform( + in_scope, + b.body.borrow() + )); + Rc::new(b_clone) + }).collect(); + let mut new_scope = in_scope.clone(); + for b in new_bindings.iter() { + new_scope.push(b.name.clone()); + } + let mut new_data = data.clone(); + new_data.bindings = new_bindings; + new_data.body = Rc::new(rewrite_identifiers_bodyform( + &new_scope, + data.body.borrow() + )); + BodyForm::Let(LetFormKind::Parallel, new_data) + } + BodyForm::Value(SExp::Atom(l,n)) => { + if !in_scope.contains(&n) { + eprintln!("n = {}", decode_string(&n)); + let idnum = n[0] as usize; + if in_scope.is_empty() { + BodyForm::Quoted(SExp::Nil(l.clone())) + } else { + let selection = in_scope[idnum % in_scope.len()].clone(); + BodyForm::Value(SExp::Atom(l.clone(),selection)) + } + } else { + BodyForm::Value(SExp::Atom(l.clone(),n.clone())) + } + } + BodyForm::Call(l,args) => { + let new_args = args.iter().enumerate().map(|(i,a)| { + if i == 0 { + a.clone() + } else { + Rc::new(rewrite_identifiers_bodyform( + in_scope, + a.borrow() + )) + } + }).collect(); + BodyForm::Call(l.clone(), new_args) + } + _ => body_form.clone() } +} +// Rewrite identifiers to match those in scope for the helper and the +// let forms. +fn rewrite_identifiers( + args: Rc, + body: &BodyForm +) -> BodyForm { + let mut in_scope = Vec::new(); + arg_identifiers(&mut in_scope, args.clone()); + rewrite_identifiers_bodyform(&in_scope, body) +} + +impl CollectProgramStructure { fn choose_with_default(&self, lst: &[T], choice: u16, default: T) -> T where T: Clone { if lst.is_empty() { return default; @@ -109,19 +209,25 @@ impl CollectProgramStructure { lst[(choice as usize) % lst.len()].clone() } + fn get_choice(&mut self) -> u16 { + if self.selectors.is_empty() { + 0 + } else { + let res = self.selectors[self.choice % self.selectors.len()]; + self.choice += 1; + res + } + } + fn new_constant( - &self, + &mut self, c: u16, - selector_choice: &mut usize, constants: &[Rc] ) -> Rc { let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); match c & 3 { - 0 => { - Rc::new(SExp::Nil(loc.clone())) - } - 1 => { + 0..1 => { let raw_number = c >> 2; let bigint = if (c & 0x2000) != 0 { @@ -150,7 +256,7 @@ impl CollectProgramStructure { _ => { // Cons. let choice_of_a = c >> 2; - let choice_of_b = self.get_selector(selector_choice); + let choice_of_b: u16 = self.get_choice(); let a = self.choose_with_default(&constants, choice_of_a, nil.clone()); let b = @@ -163,33 +269,19 @@ impl CollectProgramStructure { } fn new_argument( - &self, + &mut self, arg: u16, - selector_choice: &mut usize, atom_identifiers: &[Vec], arguments: &[Rc] ) -> Rc { let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); - match arg & 3 { + match arg & 1 { 0 => { - Rc::new(SExp::Nil(loc.clone())) - } - 1 => { - let letters = arguments.len(); - let letter1 = (letters % 25) as u8; - let letter2 = ((letters / 25) % 25) as u8; - let ident = vec![b'a' + letter1, b'a' + letter2]; - Rc::new(SExp::Atom( - loc.clone(), - ident - )) - } - 2 => { // Use 1 selector, this number is for the @ binding. let letters = arg >> 2; let ident = atom_identifiers[letters as usize % atom_identifiers.len()].clone(); - let choice = self.get_selector(selector_choice); + let choice: u16 = self.get_choice(); let bind_also = self.choose_with_default(&arguments, choice, nil.clone()); Rc::new(SExp::Cons( loc.clone(), @@ -207,7 +299,7 @@ impl CollectProgramStructure { } _ => { let choice_of_a = arg >> 2; - let choice_of_b = self.get_selector(selector_choice); + let choice_of_b: u16 = self.get_choice(); let a = self.choose_with_default(&arguments, choice_of_a, nil.clone()); let b = @@ -233,9 +325,8 @@ impl CollectProgramStructure { } fn new_bodyform( - &self, + &mut self, b: u16, - selector_choice: &mut usize, atom_identifiers: &[Vec], constants: &[Rc], arguments: &[Rc], @@ -243,25 +334,25 @@ impl CollectProgramStructure { ) -> Rc { let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); - let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); - + let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))) +; // (quote | arg | if | mult | sub | sha256 | let | call) - match b & 7 { + match b & 15 { 0 => { - let choice_of_const = b >> 3; + let choice_of_const = b >> 4; let constant = self.choose_with_default(&constants, choice_of_const, nil.clone()); let constant_borrowed: &SExp = constant.borrow(); Rc::new(BodyForm::Quoted(constant_borrowed.clone())) } - 1 => { + 1..6 => { let choice_of_arg = b >> 3; let arg = self.choose_with_default(&atom_identifiers, choice_of_arg, vec![b'X']); Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), arg))) } - 2 => { + 7 => { let choice_of_cond = b >> 3; - let choice_of_then = self.get_selector(selector_choice); - let choice_of_else = self.get_selector(selector_choice); + let choice_of_then: u16 = self.get_choice(); + let choice_of_else: u16 = self.get_choice(); let use_cond = self.choose_with_default(&body_forms, choice_of_cond, body_nil.clone()); let use_then = @@ -278,9 +369,9 @@ impl CollectProgramStructure { ] )) } - 3 => { + 8 => { let choice_of_a = b >> 3; - let choice_of_b = self.get_selector(selector_choice); + let choice_of_b: u16 = self.get_choice(); let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); let use_b = @@ -294,9 +385,9 @@ impl CollectProgramStructure { ] )) } - 4 => { + 9 => { let choice_of_a = b >> 3; - let choice_of_b = self.get_selector(selector_choice); + let choice_of_b: u16 = self.get_choice(); let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); let use_b = @@ -310,9 +401,9 @@ impl CollectProgramStructure { ] )) } - 5 => { + 10 => { let choice_of_a = b >> 3; - let choice_of_b = self.get_selector(selector_choice); + let choice_of_b: u16 = self.get_choice(); let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); let use_b = @@ -326,7 +417,7 @@ impl CollectProgramStructure { ] )) } - 6 => { + 11 => { // Synthesize a let form. let num_bindings = (b >> 3) & 3; let kind = @@ -338,8 +429,7 @@ impl CollectProgramStructure { let mut collected_names = Vec::new(); let mut collected_bindings = Vec::new(); for i in 0..=num_bindings { - let choice_of_name = - self.get_selector(selector_choice); + let choice_of_name: u16 = self.get_choice(); let choice_of_body = b >> 6; let arg_atom = atom_identifiers[choice_of_name as usize % atom_identifiers.len()].clone(); @@ -395,8 +485,7 @@ impl CollectProgramStructure { // Reference callable let mut call_args: Vec> = arg_sites.iter().map(|site| { - let choice_of_expr = - self.get_selector(selector_choice); + let choice_of_expr: u16 = self.get_choice(); self.choose_with_default(&body_forms, choice_of_expr, body_nil.clone()) }).collect(); call_args.insert(0, Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), &helper_name)))); @@ -409,10 +498,9 @@ impl CollectProgramStructure { } fn new_helper( - &self, + &mut self, i: usize, h: u16, - selector_choice: &mut usize, constants: &[Rc], arguments: &[Rc], body_forms: &[Rc], @@ -424,11 +512,14 @@ impl CollectProgramStructure { let is_inline = ((h >> 2) & 1) == 1; let choice_of_args = h >> 3; - let choice_of_body = self.get_selector(selector_choice); + let choice_of_body: u16 = self.get_choice(); let arguments = self.choose_with_default(&arguments, choice_of_args, nil.clone()); let body = - self.choose_with_default(&body_forms, choice_of_body, body_nil.clone()); + Rc::new(rewrite_identifiers( + arguments.clone(), + self.choose_with_default(&body_forms, choice_of_body, body_nil.clone()).borrow() + )); let helper_name = format!("helper_{}", i).as_bytes().to_vec(); match h & 3 { 0 => { @@ -467,30 +558,45 @@ impl CollectProgramStructure { program: Rc::new(program) }) } - } } - fn to_program(&self) -> CompileForm { + pub fn to_program(&mut self) -> CompileForm { // Build constants... let loc = Srcloc::start("*rng*"); - let mut selector_choice = 0; let nil = Rc::new(SExp::Nil(loc.clone())); let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); - let mut constants = Vec::new(); - for c in self.constants.iter() { - let new_const = self.new_constant(*c, &mut selector_choice, &constants); + let mut constants = vec![ + nil.clone(), + Rc::new(SExp::Integer(loc.clone(), bi_one())) + ]; + let constant_vals = self.constants.clone(); + for c in constant_vals.iter() { + let new_const = self.new_constant(*c, &constants); constants.push(new_const); } - let mut arguments = Vec::new(); - let mut atom_identifiers = vec![b"X".to_vec()]; + eprintln!("constants"); + for c in constants.iter() { + eprintln!(" - {}", c); + } - for arg in self.arguments.iter() { + let mut atom_identifiers = vec![ + b"A".to_vec(), + b"B".to_vec(), + b"C".to_vec(), + b"D".to_vec(), + b"E".to_vec() + ]; + let mut arguments: Vec> = atom_identifiers.iter().map(|n| { + Rc::new(SExp::Atom(loc.clone(), n.clone())) + }).collect(); + + let argument_vals = self.arguments.clone(); + for arg in argument_vals.iter() { let new_arg = self.new_argument( *arg, - &mut selector_choice, &atom_identifiers, &arguments ); @@ -500,12 +606,22 @@ impl CollectProgramStructure { arguments.push(new_arg); } + eprintln!("arguments"); + for a in arguments.iter() { + eprintln!(" - {}", a); + } + + eprintln!("identifiers"); + for i in atom_identifiers.iter() { + eprintln!(" - {}", decode_string(&i)); + } + let mut body_forms = Vec::new(); - for b in self.body_forms.iter() { + let body_vals = self.body_forms.clone(); + for b in body_vals.iter() { let new_form = self.new_bodyform( *b, - &mut selector_choice, &atom_identifiers, &constants, &arguments, @@ -514,12 +630,17 @@ impl CollectProgramStructure { body_forms.push(new_form); } + eprintln!("bodyforms"); + for b in body_forms.iter() { + eprintln!(" - {}", b.to_sexp()); + } + let mut helper_forms = Vec::new(); - for (i,h) in self.helper_structures.iter().enumerate() { + let helper_vals = self.helper_structures.clone(); + for (i,h) in helper_vals.iter().enumerate() { let new_helper = self.new_helper( i, *h, - &mut selector_choice, &constants, &arguments, &body_forms, @@ -528,24 +649,32 @@ impl CollectProgramStructure { helper_forms.push(new_helper); } + eprintln!("helpers"); + for h in helper_forms.iter() { + eprintln!(" - {}", h.to_sexp()); + } + let body = self.new_bodyform( self.main, - &mut selector_choice, &atom_identifiers, &constants, &arguments, &body_forms ); - let use_arguments = self.get_selector(&mut selector_choice); + + let use_arguments: u16 = self.get_choice(); let arguments = self.choose_with_default(&arguments, use_arguments, nil.clone()); CompileForm { loc: loc.clone(), include_forms: Vec::new(), - args: arguments, + args: arguments.clone(), helpers: helper_forms, - exp: body + exp: Rc::new(rewrite_identifiers( + arguments, + body.borrow() + )) } } } @@ -553,60 +682,50 @@ impl CollectProgramStructure { impl Distribution for Standard { fn sample(&self, rng: &mut R) -> CollectProgramStructure { let mut message_kind: u16 = MAX_ALTERNATIVE_CPS; - let mut helper_kind: u16 = MAX_HELPER_KIND_CPS; let mut iters = 0; let mut cps: CollectProgramStructure = Default::default(); let mut have_body = false; loop { - let mut input: u16 = rng.gen(); - let input_type = input & 7; - let input_val = input >> 3; - let mut have_body = false; - - iters += 1; - if iters > MAX_FORMS_CPS { - break; - } + let mut input_32: u32 = rng.gen(); - // Stop if out of range. - if input_type > MAX_ALTERNATIVE_CPS { + // Stop if zero. + if input_32 == 0 { break; } - // Stop if we get a retrograde message. - if input_type > message_kind { + iters += 1; + if iters > MAX_FORMS_CPS { break; } - // A new message type advances out of the prev phase. - message_kind = input; - match input_type { - 4 => { - let new_helper_kind = input_val & 3; - if new_helper_kind > MAX_HELPER_KIND_CPS { - message_kind += 1; - continue; + let inputs = &[(input_32 >> 16) as u16, (input_32 & 0xffff) as u16]; + for input in inputs.iter() { + let input_type = input & 15; + let input_val = input >> 4; + let mut have_body = false; + + // A new message type advances out of the prev phase. + match input_type { + 0 => { + let new_helper_kind = input_val & 3; + if new_helper_kind > MAX_HELPER_KIND_CPS { + cps.selectors.push(input_val); + continue; + } + + if new_helper_kind == 0 { + have_body = true; + cps.main = input_val; + continue; + } + + cps.helper_structures.push(input_val); } - - if new_helper_kind > helper_kind { - message_kind += 1; - continue; - } - - if new_helper_kind == 0 { - have_body = true; - cps.main = input_val; - message_kind += 1; - continue; - } - - cps.helper_structures.push(input_val); + 1..7 => cps.body_forms.push(input_val), + 8..10 => cps.arguments.push(input_val), + 11 => cps.constants.push(input_val), + _ => cps.selectors.push(input_val) } - 3 => cps.body_forms.push(input_val), - 2 => cps.arguments.push(input_val), - 1 => cps.selectors.push(input_val), - 0 => cps.constants.push(input_val), - _ => { } } } @@ -621,7 +740,7 @@ impl Distribution for Standard { #[test] fn test_make_program_structure_1() { - let mut fpr = FuzzPseudoRng::new(&[0,0,0,12,0,0,0,3,0,0,0,2,0,0,0,1,0,0,0,0]); + let mut fpr = FuzzPseudoRng::new(&[0,12,0,3,0,2,0,1,0,4]); let cps: CollectProgramStructure = fpr.gen(); let zero_u16: &[u16] = &[0]; let one_u16: &[u16] = &[1]; @@ -632,41 +751,6 @@ fn test_make_program_structure_1() { assert_eq!(&cps.constants, zero_u16); } -fn do_program(programs: &mut Vec>, unique: &mut HashSet, buf: &[u8]) { - let mut fpr = FuzzPseudoRng::new(&buf); - let cps: CollectProgramStructure = fpr.gen(); - let program = cps.to_program(); - let pts = program.to_sexp().to_string(); - if !unique.contains(&pts) { - eprintln!("{}", pts); - programs.push(buf.to_vec()); - unique.insert(pts); - } -} - -#[test] -fn test_make_program_structure_2() { - let mut rng = ChaCha8Rng::seed_from_u64(make_random_u64_seed()); - let mut buf = &[0,0,0,0]; - let this_len = buf.len(); - let mut programs = Vec::new(); - let mut unique = HashSet::new(); - do_program(&mut programs, &mut unique, buf); - for p in 0..50000 { - let choice = rng.gen_range(0..programs.len()); - let mut this_buf = programs[choice].to_vec(); - let mut next_byte = rng.gen_range(0..=buf.len()); - if next_byte == buf.len() { - this_buf.push(rng.gen()); - } else { - let next_bit = rng.gen_range(0..8); - this_buf[next_byte % this_len] ^= rng.gen::(); - } - do_program(&mut programs, &mut unique, &this_buf); - } - todo!(); -} - // We don't actually need all operators here, just a good selection with // semantics that are distinguishable. #[derive(Debug, Clone)] diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index a6e9bf043..4a774d07e 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -1,8 +1,8 @@ -#[cfg(test)] +#[cfg(any(test, feature="fuzzer"))] use rand::distributions::Standard; -#[cfg(test)] +#[cfg(any(test, feature="fuzzer"))] use rand::prelude::Distribution; -#[cfg(test)] +#[cfg(any(test, feature="fuzzer"))] use rand::Rng; use std::borrow::Borrow; @@ -49,12 +49,12 @@ pub fn random_atom_name(rng: &mut R, min_size: usize) -> Vec(rng: &mut R) -> SExp { SExp::Atom(Srcloc::start("*rng*"), random_atom_name(rng, 1)) } -#[cfg(test)] +#[cfg(any(test, feature="fuzzer"))] pub fn random_sexp(rng: &mut R, remaining: usize) -> SExp { if remaining < 2 { random_atom(rng) @@ -93,7 +93,7 @@ pub fn random_sexp(rng: &mut R, remaining: usize) -> SExp { } // Thanks: https://stackoverflow.com/questions/48490049/how-do-i-choose-a-random-value-from-an-enum -#[cfg(test)] +#[cfg(any(test, feature="fuzzer"))] impl Distribution for Standard { fn sample(&self, rng: &mut R) -> SExp { random_sexp(rng, MAX_SEXP_COST) diff --git a/src/fuzzing/fuzzrng.rs b/src/fuzzing/fuzzrng.rs index c73504dbb..db13ff592 100644 --- a/src/fuzzing/fuzzrng.rs +++ b/src/fuzzing/fuzzrng.rs @@ -11,39 +11,22 @@ use random_lfsr_256_galois::{InitRegisterPayload, LFSRGalois, LFSRGaloisBuilder} // This differs from BufRng in that it's not intended to be exhaustible since // it's being used to generate extensible data structures. pub struct FuzzPseudoRng<'slice> { - lfsr: LFSRGalois, slice: &'slice [u8], - - // Set on second or subsequent run - lfsr_scramble: bool, progress: usize, } impl<'slice> FuzzPseudoRng<'slice> { pub fn new(slice: &'slice [u8]) -> Self { - // Ensure the lfsr state is consistent so the entropy bits produce - // an identical randomness every time. - let lfsr = LFSRGaloisBuilder::new() - .set_initial_payload(InitRegisterPayload::Meander) - .build(); return FuzzPseudoRng { - lfsr: lfsr, slice: slice, - - lfsr_scramble: false, progress: 0, }; } fn next_u8_untreated(&mut self) -> u8 { - if self.slice.len() == 0 { - self.lfsr_scramble = true; + if self.progress >= self.slice.len() { return 0; } - if self.progress == self.slice.len() { - self.progress = 0; - self.lfsr_scramble = true; - } let res = self.slice[self.progress]; self.progress += 1; res @@ -67,37 +50,18 @@ impl<'slice> FuzzPseudoRng<'slice> { impl<'slice> RngCore for FuzzPseudoRng<'slice> { #[inline(always)] fn next_u32(&mut self) -> u32 { - if self.lfsr_scramble { - let lfsr32: u32 = self.lfsr.next(); - self.next_u32_untreated() ^ lfsr32 - } else { - self.next_u32_untreated() - } + self.next_u32_untreated() } #[inline(always)] fn next_u64(&mut self) -> u64 { - eprintln!("next_u64"); - if self.lfsr_scramble { - let lfsr64: u64 = self.lfsr.next(); - self.next_u64_untreated() ^ lfsr64 - } else { - self.next_u64_untreated() - } + self.next_u64_untreated() } #[inline(always)] fn fill_bytes(&mut self, dest: &mut [u8]) { - eprintln!("fill_bytes"); - if self.lfsr_scramble { - for i in 0..dest.len() { - let lfsr8: u8 = self.lfsr.next(); - dest[i] = self.next_u8_untreated() ^ lfsr8 - } - } else { - for i in 0..dest.len() { - dest[i] = self.next_u8_untreated() - } + for i in 0..dest.len() { + dest[i] = self.next_u8_untreated() } } diff --git a/src/lib.rs b/src/lib.rs index 579c4c638..ab679eca1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(exclusive_range_pattern)] + #[macro_use] extern crate lazy_static; From 8f1dfb190ea2cc05ae35c10fdb44ec67f5367aeb Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 30 Jan 2023 15:40:41 -0800 Subject: [PATCH 04/21] Add generator --- src/classic/bins/chia_prog_gen.rs | 95 +++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 src/classic/bins/chia_prog_gen.rs diff --git a/src/classic/bins/chia_prog_gen.rs b/src/classic/bins/chia_prog_gen.rs new file mode 100644 index 000000000..b06d0a5cc --- /dev/null +++ b/src/classic/bins/chia_prog_gen.rs @@ -0,0 +1,95 @@ +extern crate clvmr as clvm_rs; +use rand_chacha::ChaCha8Rng; +use rand::prelude::*; +use rand::SeedableRng; + +use std::borrow::Borrow; +use std::collections::HashSet; +use std::io::{self, BufRead, Write}; + +use std::rc::Rc; + +use clvm_rs::allocator::Allocator; + +use clvm_tools_rs::compiler::compiler::DefaultCompilerOpts; +#[cfg(feature="fuzzer")] +use clvm_tools_rs::compiler::fuzzer::CollectProgramStructure; +use clvm_tools_rs::compiler::repl::Repl; +use clvm_tools_rs::compiler::sexp::SExp; +use clvm_tools_rs::compiler::srcloc::Srcloc; + +use clvm_tools_rs::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; +#[cfg(feature="fuzzer")] +use clvm_tools_rs::fuzzing::make_random_u64_seed; +#[cfg(feature="fuzzer")] +use clvm_tools_rs::fuzzing::fuzzrng::FuzzPseudoRng; + +#[cfg(feature="fuzzer")] +fn do_program(programs: &mut Vec>, unique: &mut HashSet, dialect: Rc, buf: &[u8]) { + let mut fpr = FuzzPseudoRng::new(&buf); + let mut cps: CollectProgramStructure = fpr.gen(); + let program = cps.to_program(); + let pt = program.to_sexp(); + let pts = program.to_sexp().to_string(); + if !unique.contains(&pts) { + if let SExp::Cons(_,args,body) = pt.borrow() { + let include_directive = Rc::new(SExp::Cons( + pt.loc(), + Rc::new(SExp::atom_from_string(pt.loc(), "include")), + Rc::new(SExp::Cons( + pt.loc(), + dialect, + Rc::new(SExp::Nil(pt.loc())) + )) + )); + let new_mod = SExp::Cons( + pt.loc(), + Rc::new(SExp::atom_from_string(pt.loc(), "mod")), + Rc::new(SExp::Cons( + pt.loc(), + args.clone(), + Rc::new(SExp::Cons( + pt.loc(), + include_directive, + body.clone() + )) + )) + ); + println!("{}", new_mod); + programs.push(buf.to_vec()); + unique.insert(pts); + } + } +} + +#[cfg(feature="fuzzer")] +fn main() { + let mut rng = ChaCha8Rng::seed_from_u64(make_random_u64_seed()); + let mut buf = &[0,0,0,0]; + let this_len = buf.len(); + let mut programs = Vec::new(); + let mut unique = HashSet::new(); + let loc = Srcloc::start("*rng*"); + let dialect = Rc::new(SExp::atom_from_string(loc, "*standard-cl-21*")); + do_program(&mut programs, &mut unique, dialect.clone(), buf); + for p in 0..200000 { + let choice = rng.gen_range(0..programs.len()); + let mut this_buf = programs[choice].to_vec(); + let mut next_byte = rng.gen_range(0..=buf.len()); + if next_byte >= buf.len() - 3 { + for i in 0..4 { + this_buf.push(rng.gen()); + } + } else { + for i in 0..4 { + let next_bit = rng.gen_range(0..8); + this_buf[next_byte + i] ^= rng.gen::(); + } + } + do_program(&mut programs, &mut unique, dialect.clone(), &this_buf); + } +} + +#[cfg(not(feature="fuzzer"))] +fn main() { +} From e0cc089409a052b73281199f4eca9b5e837dc7c3 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 30 Jan 2023 15:41:57 -0800 Subject: [PATCH 05/21] Remove until we replace this test --- src/compiler/fuzzer.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index 89ae39d05..8cab6173f 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -738,19 +738,6 @@ impl Distribution for Standard { } } -#[test] -fn test_make_program_structure_1() { - let mut fpr = FuzzPseudoRng::new(&[0,12,0,3,0,2,0,1,0,4]); - let cps: CollectProgramStructure = fpr.gen(); - let zero_u16: &[u16] = &[0]; - let one_u16: &[u16] = &[1]; - assert_eq!(&cps.helper_structures, one_u16); - assert_eq!(&cps.body_forms, zero_u16); - assert_eq!(&cps.arguments, zero_u16); - assert_eq!(&cps.selectors, zero_u16); - assert_eq!(&cps.constants, zero_u16); -} - // We don't actually need all operators here, just a good selection with // semantics that are distinguishable. #[derive(Debug, Clone)] From ca9cc8acefd99d7dbb245e76fc2c133d2103fc79 Mon Sep 17 00:00:00 2001 From: arty Date: Mon, 30 Jan 2023 23:18:58 -0800 Subject: [PATCH 06/21] Proggen --- Cargo.toml | 7 +- src/classic/bins/chia_prog_gen.rs | 95 --- src/compiler/fuzzer.rs | 26 - test/proggen/Cargo.lock | 1016 +++++++++++++++++++++++++++++ test/proggen/Cargo.toml | 17 + test/proggen/src/main.rs | 110 ++++ 6 files changed, 1144 insertions(+), 127 deletions(-) delete mode 100644 src/classic/bins/chia_prog_gen.rs create mode 100644 test/proggen/Cargo.lock create mode 100644 test/proggen/Cargo.toml create mode 100644 test/proggen/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 5c0deb8b7..8c9c653ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ indoc = "1.0" do-notation = "0.1.3" serde_json = "1.0" sha2 = "0.9.5" -rand = "0.8.4" +rand = "0.8.5" tempfile = "3.3.0" clvmr = "0.1.24" binascii = "0.1.4" @@ -90,8 +90,3 @@ path = "src/classic/bins/shrink.rs" [[bin]] name = "repl" path = "src/classic/bins/repl.rs" - -[[bin]] -name = "chia_prog_gen" -path = "src/classic/bins/chia_prog_gen.rs" -default-features = ["fuzzer"] \ No newline at end of file diff --git a/src/classic/bins/chia_prog_gen.rs b/src/classic/bins/chia_prog_gen.rs deleted file mode 100644 index b06d0a5cc..000000000 --- a/src/classic/bins/chia_prog_gen.rs +++ /dev/null @@ -1,95 +0,0 @@ -extern crate clvmr as clvm_rs; -use rand_chacha::ChaCha8Rng; -use rand::prelude::*; -use rand::SeedableRng; - -use std::borrow::Borrow; -use std::collections::HashSet; -use std::io::{self, BufRead, Write}; - -use std::rc::Rc; - -use clvm_rs::allocator::Allocator; - -use clvm_tools_rs::compiler::compiler::DefaultCompilerOpts; -#[cfg(feature="fuzzer")] -use clvm_tools_rs::compiler::fuzzer::CollectProgramStructure; -use clvm_tools_rs::compiler::repl::Repl; -use clvm_tools_rs::compiler::sexp::SExp; -use clvm_tools_rs::compiler::srcloc::Srcloc; - -use clvm_tools_rs::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; -#[cfg(feature="fuzzer")] -use clvm_tools_rs::fuzzing::make_random_u64_seed; -#[cfg(feature="fuzzer")] -use clvm_tools_rs::fuzzing::fuzzrng::FuzzPseudoRng; - -#[cfg(feature="fuzzer")] -fn do_program(programs: &mut Vec>, unique: &mut HashSet, dialect: Rc, buf: &[u8]) { - let mut fpr = FuzzPseudoRng::new(&buf); - let mut cps: CollectProgramStructure = fpr.gen(); - let program = cps.to_program(); - let pt = program.to_sexp(); - let pts = program.to_sexp().to_string(); - if !unique.contains(&pts) { - if let SExp::Cons(_,args,body) = pt.borrow() { - let include_directive = Rc::new(SExp::Cons( - pt.loc(), - Rc::new(SExp::atom_from_string(pt.loc(), "include")), - Rc::new(SExp::Cons( - pt.loc(), - dialect, - Rc::new(SExp::Nil(pt.loc())) - )) - )); - let new_mod = SExp::Cons( - pt.loc(), - Rc::new(SExp::atom_from_string(pt.loc(), "mod")), - Rc::new(SExp::Cons( - pt.loc(), - args.clone(), - Rc::new(SExp::Cons( - pt.loc(), - include_directive, - body.clone() - )) - )) - ); - println!("{}", new_mod); - programs.push(buf.to_vec()); - unique.insert(pts); - } - } -} - -#[cfg(feature="fuzzer")] -fn main() { - let mut rng = ChaCha8Rng::seed_from_u64(make_random_u64_seed()); - let mut buf = &[0,0,0,0]; - let this_len = buf.len(); - let mut programs = Vec::new(); - let mut unique = HashSet::new(); - let loc = Srcloc::start("*rng*"); - let dialect = Rc::new(SExp::atom_from_string(loc, "*standard-cl-21*")); - do_program(&mut programs, &mut unique, dialect.clone(), buf); - for p in 0..200000 { - let choice = rng.gen_range(0..programs.len()); - let mut this_buf = programs[choice].to_vec(); - let mut next_byte = rng.gen_range(0..=buf.len()); - if next_byte >= buf.len() - 3 { - for i in 0..4 { - this_buf.push(rng.gen()); - } - } else { - for i in 0..4 { - let next_bit = rng.gen_range(0..8); - this_buf[next_byte + i] ^= rng.gen::(); - } - } - do_program(&mut programs, &mut unique, dialect.clone(), &this_buf); - } -} - -#[cfg(not(feature="fuzzer"))] -fn main() { -} diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index 8cab6173f..9973a40bc 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -160,7 +160,6 @@ fn rewrite_identifiers_bodyform( } BodyForm::Value(SExp::Atom(l,n)) => { if !in_scope.contains(&n) { - eprintln!("n = {}", decode_string(&n)); let idnum = n[0] as usize; if in_scope.is_empty() { BodyForm::Quoted(SExp::Nil(l.clone())) @@ -577,11 +576,6 @@ impl CollectProgramStructure { constants.push(new_const); } - eprintln!("constants"); - for c in constants.iter() { - eprintln!(" - {}", c); - } - let mut atom_identifiers = vec![ b"A".to_vec(), b"B".to_vec(), @@ -606,16 +600,6 @@ impl CollectProgramStructure { arguments.push(new_arg); } - eprintln!("arguments"); - for a in arguments.iter() { - eprintln!(" - {}", a); - } - - eprintln!("identifiers"); - for i in atom_identifiers.iter() { - eprintln!(" - {}", decode_string(&i)); - } - let mut body_forms = Vec::new(); let body_vals = self.body_forms.clone(); @@ -630,11 +614,6 @@ impl CollectProgramStructure { body_forms.push(new_form); } - eprintln!("bodyforms"); - for b in body_forms.iter() { - eprintln!(" - {}", b.to_sexp()); - } - let mut helper_forms = Vec::new(); let helper_vals = self.helper_structures.clone(); for (i,h) in helper_vals.iter().enumerate() { @@ -649,11 +628,6 @@ impl CollectProgramStructure { helper_forms.push(new_helper); } - eprintln!("helpers"); - for h in helper_forms.iter() { - eprintln!(" - {}", h.to_sexp()); - } - let body = self.new_bodyform( self.main, &atom_identifiers, diff --git a/test/proggen/Cargo.lock b/test/proggen/Cargo.lock new file mode 100644 index 000000000..f237c0b79 --- /dev/null +++ b/test/proggen/Cargo.lock @@ -0,0 +1,1016 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "binascii" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bls12_381" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62250ece575fa9b22068b3a8d59586f01d426dd7785522efd97632959e71c986" +dependencies = [ + "ff", + "group", + "pairing", + "rand_core", + "subtle", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytestream" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f720842a717d6afaf69fee2dc69b771edc165f12cc3eb1b0e8eeef53a86454" +dependencies = [ + "byteorder", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clvm_tools_rs" +version = "0.1.30" +dependencies = [ + "binascii", + "bls12_381", + "bytestream", + "clvmr", + "derivative", + "do-notation", + "encoding8", + "getrandom", + "hex", + "indoc 1.0.9", + "js-sys", + "lazy_static", + "linked-hash-map", + "num", + "num-bigint", + "num-traits", + "pyo3", + "pyo3-build-config 0.15.2", + "rand", + "rand_chacha", + "random_lfsr_256_galois", + "serde_json", + "sha2 0.9.9", + "tempfile", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-test", + "yaml-rust", +] + +[[package]] +name = "clvmr" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5e907612d322d0d7def6b0ecb3ad681f6af2db106bcfabe4153746c60ef9e4" +dependencies = [ + "bls12_381", + "hex", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "sha2 0.10.2", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.3", + "crypto-common", +] + +[[package]] +name = "do-notation" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e16a80c1dda2cf52fa07106427d3d798b6331dca8155fcb8c39f7fc78f6dd2" + +[[package]] +name = "encoding8" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3144e455c7aeda487c72555cac2ef84ccac173b29a57b07382ba27016e57b246" + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "indoc" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8" +dependencies = [ + "indoc-impl", + "proc-macro-hack", +] + +[[package]] +name = "indoc" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" + +[[package]] +name = "indoc-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0" +dependencies = [ + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", + "unindent", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pairing" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b" +dependencies = [ + "group", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "paste" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880" +dependencies = [ + "paste-impl", + "proc-macro-hack", +] + +[[package]] +name = "paste-impl" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6" +dependencies = [ + "proc-macro-hack", +] + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proggen" +version = "0.1.0" +dependencies = [ + "base64", + "clvm_tools_rs", + "clvmr", + "rand", + "rand_chacha", + "sqlite", +] + +[[package]] +name = "pyo3" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35100f9347670a566a67aa623369293703322bb9db77d99d7df7313b575ae0c8" +dependencies = [ + "cfg-if", + "indoc 0.3.6", + "libc", + "parking_lot", + "paste", + "pyo3-build-config 0.14.5", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d12961738cacbd7f91b7c43bc25cfeeaa2698ad07a04b3be0aa88b950865738f" +dependencies = [ + "once_cell", +] + +[[package]] +name = "pyo3-build-config" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "779239fc40b8e18bc8416d3a37d280ca9b9fb04bda54b98037bb6748595c2410" +dependencies = [ + "once_cell", +] + +[[package]] +name = "pyo3-macros" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0bc5215d704824dfddddc03f93cb572e1155c68b6761c37005e1c288808ea8" +dependencies = [ + "pyo3-macros-backend", + "quote", + "syn", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71623fc593224afaab918aa3afcaf86ed2f43d34f6afde7f3922608f253240df" +dependencies = [ + "proc-macro2", + "pyo3-build-config 0.14.5", + "quote", + "syn", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "random_lfsr_256_galois" +version = "22.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e049eaa77d779d2abb9e36bfaca1708fa3c985a796d19a160676432fcda420" +dependencies = [ + "num-traits", + "rand", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.6", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "sqlite" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12e072cb5fb89b3fe5e9c9584676348feb503f9fb3ae829d9868171bc5372d48" +dependencies = [ + "libc", + "sqlite3-sys", +] + +[[package]] +name = "sqlite3-src" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1815a7a02c996eb8e5c64f61fcb6fd9b12e593ce265c512c5853b2513635691" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "sqlite3-sys" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d47c99824fc55360ba00caf28de0b8a0458369b832e016a64c13af0ad9fbb9ee" +dependencies = [ + "libc", + "sqlite3-src", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-segmentation" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" + +[[package]] +name = "unindent" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d2fff962180c3fadf677438054b1db62bee4aa32af26a45388af07d1287e1d" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4683da3dfc016f704c9f82cf401520c4f1cb3ee440f7f52b3d6ac29506a49ca7" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/test/proggen/Cargo.toml b/test/proggen/Cargo.toml new file mode 100644 index 000000000..d4aeb5e64 --- /dev/null +++ b/test/proggen/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "proggen" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +sqlite = "0.30.0" +base64 = "0.21.0" +clvmr = "0.1.24" +rand_chacha = "0.3.1" +rand = "0.8.5" + +[dependencies.clvm_tools_rs] +path = "../.." +features = ["fuzzer"] \ No newline at end of file diff --git a/test/proggen/src/main.rs b/test/proggen/src/main.rs new file mode 100644 index 000000000..5fdbb0a4c --- /dev/null +++ b/test/proggen/src/main.rs @@ -0,0 +1,110 @@ +extern crate clvmr as clvm_rs; +use rand_chacha::ChaCha8Rng; +use rand::prelude::*; +use rand::SeedableRng; + +use sqlite; +use base64::{Engine as _, engine::general_purpose}; + +use std::borrow::Borrow; +use std::io::{self, BufRead, Write}; + +use std::rc::Rc; + +use clvm_rs::allocator::Allocator; + +use clvm_tools_rs::compiler::fuzzer::CollectProgramStructure; +use clvm_tools_rs::compiler::sexp::SExp; +use clvm_tools_rs::compiler::srcloc::Srcloc; + +use clvm_tools_rs::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; +use clvm_tools_rs::fuzzing::make_random_u64_seed; +use clvm_tools_rs::fuzzing::fuzzrng::FuzzPseudoRng; + +fn do_program(db: &mut sqlite::Connection, dialect: Rc, buf: &[u8]) -> Rc { + let mut fpr = FuzzPseudoRng::new(&buf); + let mut cps: CollectProgramStructure = fpr.gen(); + let program = cps.to_program(); + let pt = program.to_sexp(); + if let SExp::Cons(_,args,body) = pt.borrow() { + let include_directive = Rc::new(SExp::Cons( + pt.loc(), + Rc::new(SExp::atom_from_string(pt.loc(), "include")), + Rc::new(SExp::Cons( + pt.loc(), + dialect, + Rc::new(SExp::Nil(pt.loc())) + )) + )); + Rc::new(SExp::Cons( + pt.loc(), + Rc::new(SExp::atom_from_string(pt.loc(), "mod")), + Rc::new(SExp::Cons( + pt.loc(), + args.clone(), + Rc::new(SExp::Cons( + pt.loc(), + include_directive, + body.clone() + )) + )) + )) + } else { + pt + } +} + +fn write_prog_to_db(db: &mut sqlite::Connection, buf: &[u8], sexp: Rc) { + let pts = sexp.to_string(); + let encoded: String = general_purpose::STANDARD.encode(buf); + let mut stmt = db.prepare("insert or ignore into programs (b, t) values (?, ?)").expect("should work"); + let binds: &[sqlite::Value] = + &[sqlite::Value::String(encoded), sqlite::Value::String(pts)]; + stmt.bind(binds).unwrap(); + stmt.next().expect("should work"); +} + +fn main() { + let mut rng = ChaCha8Rng::seed_from_u64(make_random_u64_seed()); + let mut buf = vec![0,0,0,0]; + + let mut conn = sqlite::open("prog.db").expect("db"); + + if let Err(_) = conn.execute("create table if not exists programs (b text primary key, t text)") { + eprintln!("failed to create db"); + return; + } + + let this_len = buf.len(); + let loc = Srcloc::start("*rng*"); + let dialect = Rc::new(SExp::atom_from_string(loc, "*standard-cl-21*")); + + let sexp = do_program(&mut conn, dialect.clone(), &buf); + write_prog_to_db(&mut conn, &buf, sexp); + + for p in 0..200000 { + // Read a random row. + { + let mut stmt = conn.prepare("SELECT b as b FROM programs ORDER BY RANDOM() LIMIT 1;").expect("should have selectable stuff"); + + if let Ok(sqlite::State::Row) = stmt.next() { + let this_buf_repr = stmt.read::("b").expect("should have the right column"); + buf = general_purpose::STANDARD.decode(this_buf_repr).expect("should exist"); + } + } + + let mut next_byte = rng.gen_range(0..=buf.len()); + if next_byte >= buf.len() - 3 { + for i in 0..4 { + buf.push(rng.gen()); + } + } else { + for i in 0..4 { + buf[next_byte + i] ^= rng.gen::(); + } + } + let sexp = do_program(&mut conn, dialect.clone(), &buf); + eprintln!("{}", sexp); + write_prog_to_db(&mut conn, &buf, sexp); + } +} From 5dee37d3060b825762889ea29966539f9c759127 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Jan 2023 03:58:26 -0800 Subject: [PATCH 07/21] clippy + fmt + fixes --- src/compiler/fuzzer.rs | 370 ++++++++++++++++----------------------- src/compiler/sexp.rs | 12 +- src/fuzzing/fuzzrng.rs | 10 +- src/lib.rs | 2 +- test/proggen/src/main.rs | 68 ++++--- 5 files changed, 191 insertions(+), 271 deletions(-) diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index 9973a40bc..bb452210a 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -1,19 +1,19 @@ use num_bigint::{BigInt, ToBigInt}; -use num_traits::ToPrimitive; use rand::distributions::Standard; use rand::prelude::*; use rand::Rng; -use rand_chacha::ChaCha8Rng; use std::borrow::Borrow; use std::cmp::max; -use std::collections::HashSet; use std::rc::Rc; use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; use crate::compiler::clvm::truthy; use crate::compiler::codegen::create_name_lookup_; -use crate::compiler::comptypes::{Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, LetData, LetFormKind, HelperForm}; +use crate::compiler::comptypes::{ + Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, HelperForm, LetData, + LetFormKind, +}; use crate::compiler::sexp::{enlist, SExp}; use crate::compiler::sexp::{random_atom_name, random_sexp}; @@ -21,22 +21,15 @@ use crate::compiler::sexp::{random_atom_name, random_sexp}; use crate::classic::clvm::__type_compatibility__::{sha256, Bytes, BytesFromType, Stream}; use crate::classic::clvm::casts::bigint_to_bytes_clvm; use crate::compiler::runtypes::RunFailure; -use crate::compiler::sexp::decode_string; use crate::compiler::srcloc::Srcloc; -#[cfg(any(test, feature="fuzzer"))] -use crate::fuzzing::fuzzrng::FuzzPseudoRng; -#[cfg(any(test, feature="fuzzer"))] -use crate::fuzzing::make_random_u64_seed; - -use crate::util::{number_from_u8, Number}; +use crate::util::Number; const MIN_ARGLIST: usize = 3; const MAX_STEPS: usize = 1000; pub const MAX_LIST_BOUND: usize = 3; const CURRENT_DIALECT: u32 = 21; const BINDING_NAME_MIN: usize = 3; -const MAX_ALTERNATIVE_CPS: u16 = 5; const MAX_FORMS_CPS: usize = 512; const MAX_HELPER_KIND_CPS: u16 = 3; @@ -90,117 +83,109 @@ pub struct CollectProgramStructure { selectors: Vec, constants: Vec, choice: usize, - main: u16 + main: u16, } -fn arg_identifiers( - in_scope: &mut Vec>, - args: Rc -) { +fn arg_identifiers(in_scope: &mut Vec>, args: Rc) { match args.borrow() { - SExp::Cons(_,a,b) => { + SExp::Cons(_, a, b) => { arg_identifiers(in_scope, a.clone()); arg_identifiers(in_scope, b.clone()); } - SExp::Atom(_,n) => { + SExp::Atom(_, n) => { if n != b"@" { in_scope.push(n.clone()); } } - _ => { } + _ => {} } } -fn rewrite_identifiers_bodyform( - in_scope: &Vec>, - body_form: &BodyForm -) -> BodyForm { +fn rewrite_identifiers_bodyform(in_scope: &Vec>, body_form: &BodyForm) -> BodyForm { match body_form { BodyForm::Let(LetFormKind::Sequential, data) => { - let mut newly_bound = in_scope.clone(); let mut new_bindings = Vec::new(); + let mut newly_bound = in_scope.clone(); for b in data.bindings.iter() { - let new_binding_body = rewrite_identifiers_bodyform( - &newly_bound, - b.body.borrow() - ); + let new_binding_body = rewrite_identifiers_bodyform(&newly_bound, b.body.borrow()); newly_bound.push(b.name.clone()); + let new_binding_data_borrowed: &Binding = b.borrow(); + let mut new_binding_data_cloned = new_binding_data_borrowed.clone(); + new_binding_data_cloned.body = Rc::new(new_binding_body); + new_bindings.push(Rc::new(new_binding_data_cloned)); } let mut new_data = data.clone(); new_data.bindings = new_bindings; - let new_body = rewrite_identifiers_bodyform( - &newly_bound, data.body.borrow() - ); + let new_body = rewrite_identifiers_bodyform(&newly_bound, data.body.borrow()); new_data.body = Rc::new(new_body); BodyForm::Let(LetFormKind::Sequential, new_data) } BodyForm::Let(LetFormKind::Parallel, data) => { - let new_bindings: Vec> = data.bindings.iter().map(|b| { - let mut b_borrowed: &Binding = b.borrow(); - let mut b_clone = b_borrowed.clone(); - b_clone.body = Rc::new(rewrite_identifiers_bodyform( - in_scope, - b.body.borrow() - )); - Rc::new(b_clone) - }).collect(); + let new_bindings: Vec> = data + .bindings + .iter() + .map(|b| { + let b_borrowed: &Binding = b.borrow(); + let mut b_clone = b_borrowed.clone(); + b_clone.body = Rc::new(rewrite_identifiers_bodyform(in_scope, b.body.borrow())); + Rc::new(b_clone) + }) + .collect(); let mut new_scope = in_scope.clone(); for b in new_bindings.iter() { new_scope.push(b.name.clone()); } let mut new_data = data.clone(); new_data.bindings = new_bindings; - new_data.body = Rc::new(rewrite_identifiers_bodyform( - &new_scope, - data.body.borrow() - )); + new_data.body = Rc::new(rewrite_identifiers_bodyform(&new_scope, data.body.borrow())); BodyForm::Let(LetFormKind::Parallel, new_data) } - BodyForm::Value(SExp::Atom(l,n)) => { + BodyForm::Value(SExp::Atom(l, n)) => { if !in_scope.contains(&n) { let idnum = n[0] as usize; if in_scope.is_empty() { BodyForm::Quoted(SExp::Nil(l.clone())) } else { let selection = in_scope[idnum % in_scope.len()].clone(); - BodyForm::Value(SExp::Atom(l.clone(),selection)) + BodyForm::Value(SExp::Atom(l.clone(), selection)) } } else { - BodyForm::Value(SExp::Atom(l.clone(),n.clone())) + BodyForm::Value(SExp::Atom(l.clone(), n.clone())) } } - BodyForm::Call(l,args) => { - let new_args = args.iter().enumerate().map(|(i,a)| { - if i == 0 { - a.clone() - } else { - Rc::new(rewrite_identifiers_bodyform( - in_scope, - a.borrow() - )) - } - }).collect(); + BodyForm::Call(l, args) => { + let new_args = args + .iter() + .enumerate() + .map(|(i, a)| { + if i == 0 { + a.clone() + } else { + Rc::new(rewrite_identifiers_bodyform(in_scope, a.borrow())) + } + }) + .collect(); BodyForm::Call(l.clone(), new_args) } - _ => body_form.clone() + _ => body_form.clone(), } } // Rewrite identifiers to match those in scope for the helper and the // let forms. -fn rewrite_identifiers( - args: Rc, - body: &BodyForm -) -> BodyForm { +fn rewrite_identifiers(args: Rc, body: &BodyForm) -> BodyForm { let mut in_scope = Vec::new(); arg_identifiers(&mut in_scope, args.clone()); rewrite_identifiers_bodyform(&in_scope, body) } impl CollectProgramStructure { - fn choose_with_default(&self, lst: &[T], choice: u16, default: T) -> T where T: Clone { + fn choose_with_default(&self, lst: &[T], choice: u16, default: T) -> T + where + T: Clone, + { if lst.is_empty() { return default; } @@ -218,22 +203,13 @@ impl CollectProgramStructure { } } - fn new_constant( - &mut self, - c: u16, - constants: &[Rc] - ) -> Rc { + fn new_constant(&mut self, c: u16, constants: &[Rc]) -> Rc { let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); match c & 3 { 0..1 => { - let raw_number = c >> 2; - let bigint = - if (c & 0x2000) != 0 { - (-(c as i32)).to_bigint().unwrap() - } else { - c.to_bigint().unwrap() - }; + let raw_number = c & 0x3fff; + let bigint = (raw_number - 0x2000).to_bigint().unwrap(); Rc::new(SExp::Integer(loc.clone(), bigint)) } 2 => { @@ -242,12 +218,10 @@ impl CollectProgramStructure { // them. let new_byte = ((c >> 2) & 0xff) as u8; if !constants.is_empty() { - if let SExp::Atom(l,n) = constants[constants.len()-1].borrow() { + if let SExp::Atom(l, n) = constants[constants.len() - 1].borrow() { let mut new_atom_content = n.to_vec(); new_atom_content.push(new_byte); - return Rc::new(SExp::Atom( - l.clone(), new_atom_content - )); + return Rc::new(SExp::Atom(l.clone(), new_atom_content)); } } Rc::new(SExp::Atom(loc.clone(), vec![new_byte])) @@ -256,13 +230,9 @@ impl CollectProgramStructure { // Cons. let choice_of_a = c >> 2; let choice_of_b: u16 = self.get_choice(); - let a = - self.choose_with_default(&constants, choice_of_a, nil.clone()); - let b = - self.choose_with_default(&constants, choice_of_b, nil.clone()); - Rc::new(SExp::Cons( - loc.clone(), a, b - )) + let a = self.choose_with_default(&constants, choice_of_a, nil.clone()); + let b = self.choose_with_default(&constants, choice_of_b, nil.clone()); + Rc::new(SExp::Cons(loc.clone(), a, b)) } } } @@ -271,7 +241,7 @@ impl CollectProgramStructure { &mut self, arg: u16, atom_identifiers: &[Vec], - arguments: &[Rc] + arguments: &[Rc], ) -> Rc { let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); @@ -291,30 +261,22 @@ impl CollectProgramStructure { Rc::new(SExp::Cons( loc.clone(), bind_also, - Rc::new(SExp::Nil(loc.clone())) - )) - )) + Rc::new(SExp::Nil(loc.clone())), + )), + )), )) } _ => { let choice_of_a = arg >> 2; let choice_of_b: u16 = self.get_choice(); - let a = - self.choose_with_default(&arguments, choice_of_a, nil.clone()); - let b = - self.choose_with_default(&arguments, choice_of_b, nil.clone()); - Rc::new(SExp::Cons( - loc.clone(), a, b - )) + let a = self.choose_with_default(&arguments, choice_of_a, nil.clone()); + let b = self.choose_with_default(&arguments, choice_of_b, nil.clone()); + Rc::new(SExp::Cons(loc.clone(), a, b)) } } } - fn isolate_arg_sites( - &self, - arg_sites: &mut Vec>, - args: Rc, - ) { + fn isolate_arg_sites(&self, arg_sites: &mut Vec>, args: Rc) { if let SExp::Cons(_, f, r) = args.borrow() { arg_sites.push(f.clone()); self.isolate_arg_sites(arg_sites, r.clone()); @@ -329,12 +291,11 @@ impl CollectProgramStructure { atom_identifiers: &[Vec], constants: &[Rc], arguments: &[Rc], - body_forms: &[Rc] + body_forms: &[Rc], ) -> Rc { let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); - let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))) -; + let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); // (quote | arg | if | mult | sub | sha256 | let | call) match b & 15 { 0 => { @@ -364,70 +325,63 @@ impl CollectProgramStructure { Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), "if"))), use_cond, use_then, - use_else - ] + use_else, + ], )) } 8 => { let choice_of_a = b >> 3; let choice_of_b: u16 = self.get_choice(); - let use_a = - self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); - let use_b = - self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); + let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); + let use_b = self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); Rc::new(BodyForm::Call( loc.clone(), vec![ Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![18]))), use_a, - use_b - ] + use_b, + ], )) } 9 => { let choice_of_a = b >> 3; let choice_of_b: u16 = self.get_choice(); - let use_a = - self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); - let use_b = - self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); + let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); + let use_b = self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); Rc::new(BodyForm::Call( loc.clone(), vec![ Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![17]))), use_a, - use_b - ] + use_b, + ], )) } 10 => { let choice_of_a = b >> 3; let choice_of_b: u16 = self.get_choice(); - let use_a = - self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); - let use_b = - self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); + let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); + let use_b = self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); Rc::new(BodyForm::Call( loc.clone(), vec![ Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![11]))), use_a, - use_b - ] + use_b, + ], )) } 11 => { // Synthesize a let form. let num_bindings = (b >> 3) & 3; - let kind = - if (b >> 5) != 0 { - LetFormKind::Parallel - } else { - LetFormKind::Sequential - }; + let kind = if (b >> 5) != 0 { + LetFormKind::Parallel + } else { + LetFormKind::Sequential + }; let mut collected_names = Vec::new(); let mut collected_bindings = Vec::new(); - for i in 0..=num_bindings { + for _ in 0..=num_bindings { let choice_of_name: u16 = self.get_choice(); let choice_of_body = b >> 6; let arg_atom = @@ -444,12 +398,11 @@ impl CollectProgramStructure { loc: loc.clone(), nl: loc.clone(), name: arg_atom, - body: body + body: body, })); } - let body = - self.choose_with_default(&body_forms, b >> 5, body_nil.clone()); + let body = self.choose_with_default(&body_forms, b >> 5, body_nil.clone()); Rc::new(BodyForm::Let( kind, @@ -457,8 +410,8 @@ impl CollectProgramStructure { loc: loc.clone(), kw: None, bindings: collected_bindings, - body: body - } + body: body, + }, )) } _ => { @@ -468,30 +421,37 @@ impl CollectProgramStructure { } let choice_of_helper = (b >> 3) as usize % self.helper_structures.len(); - let helper_spec = - self.helper_structures[choice_of_helper as usize % self.helper_structures.len()]; + let helper_spec = self.helper_structures + [choice_of_helper as usize % self.helper_structures.len()]; let choice_of_arg = helper_spec >> 3; - let call_args = - self.choose_with_default(&arguments, choice_of_arg, nil.clone()); + let call_args = self.choose_with_default(&arguments, choice_of_arg, nil.clone()); let mut arg_sites = Vec::new(); self.isolate_arg_sites(&mut arg_sites, call_args); let helper_name = format!("helper_{}", choice_of_helper); if helper_spec & 3 == 0 { // Reference constant - return Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), &helper_name))); + return Rc::new(BodyForm::Value(SExp::atom_from_string( + loc.clone(), + &helper_name, + ))); } // Reference callable - let mut call_args: Vec> = - arg_sites.iter().map(|site| { + let mut call_args: Vec> = arg_sites + .iter() + .map(|_| { let choice_of_expr: u16 = self.get_choice(); self.choose_with_default(&body_forms, choice_of_expr, body_nil.clone()) - }).collect(); - call_args.insert(0, Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), &helper_name)))); - Rc::new(BodyForm::Call( - loc.clone(), - call_args - )) + }) + .collect(); + call_args.insert( + 0, + Rc::new(BodyForm::Value(SExp::atom_from_string( + loc.clone(), + &helper_name, + ))), + ); + Rc::new(BodyForm::Call(loc.clone(), call_args)) } } } @@ -500,10 +460,9 @@ impl CollectProgramStructure { &mut self, i: usize, h: u16, - constants: &[Rc], arguments: &[Rc], body_forms: &[Rc], - helper_forms: &[HelperForm] + helper_forms: &[HelperForm], ) -> HelperForm { let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); @@ -512,41 +471,39 @@ impl CollectProgramStructure { let is_inline = ((h >> 2) & 1) == 1; let choice_of_args = h >> 3; let choice_of_body: u16 = self.get_choice(); - let arguments = - self.choose_with_default(&arguments, choice_of_args, nil.clone()); - let body = - Rc::new(rewrite_identifiers( - arguments.clone(), - self.choose_with_default(&body_forms, choice_of_body, body_nil.clone()).borrow() - )); + let arguments = self.choose_with_default(&arguments, choice_of_args, nil.clone()); + let body = Rc::new(rewrite_identifiers( + arguments.clone(), + self.choose_with_default(&body_forms, choice_of_body, body_nil.clone()) + .borrow(), + )); let helper_name = format!("helper_{}", i).as_bytes().to_vec(); match h & 3 { - 0 => { - HelperForm::Defconstant(DefconstData { - loc: loc.clone(), - name: helper_name, - kw: None, - nl: loc.clone(), - body: body - }) - } - 1 => { - HelperForm::Defun(is_inline, DefunData { + 0 => HelperForm::Defconstant(DefconstData { + loc: loc.clone(), + name: helper_name, + kw: None, + nl: loc.clone(), + body: body, + }), + 1 => HelperForm::Defun( + is_inline, + DefunData { loc: loc.clone(), name: helper_name, kw: None, nl: loc.clone(), args: arguments, - body - }) - } + body, + }, + ), _ => { let program = CompileForm { loc: loc.clone(), include_forms: Vec::new(), args: arguments.clone(), helpers: helper_forms.to_vec(), - exp: body + exp: body, }; HelperForm::Defmacro(DefmacData { loc: loc.clone(), @@ -554,7 +511,7 @@ impl CollectProgramStructure { kw: None, nl: loc.clone(), args: arguments, - program: Rc::new(program) + program: Rc::new(program), }) } } @@ -564,12 +521,8 @@ impl CollectProgramStructure { // Build constants... let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); - let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); - let mut constants = vec![ - nil.clone(), - Rc::new(SExp::Integer(loc.clone(), bi_one())) - ]; + let mut constants = vec![nil.clone(), Rc::new(SExp::Integer(loc.clone(), bi_one()))]; let constant_vals = self.constants.clone(); for c in constant_vals.iter() { let new_const = self.new_constant(*c, &constants); @@ -581,20 +534,17 @@ impl CollectProgramStructure { b"B".to_vec(), b"C".to_vec(), b"D".to_vec(), - b"E".to_vec() + b"E".to_vec(), ]; - let mut arguments: Vec> = atom_identifiers.iter().map(|n| { - Rc::new(SExp::Atom(loc.clone(), n.clone())) - }).collect(); + let mut arguments: Vec> = atom_identifiers + .iter() + .map(|n| Rc::new(SExp::Atom(loc.clone(), n.clone()))) + .collect(); let argument_vals = self.arguments.clone(); for arg in argument_vals.iter() { - let new_arg = self.new_argument( - *arg, - &atom_identifiers, - &arguments - ); - if let SExp::Atom(_,n) = new_arg.borrow() { + let new_arg = self.new_argument(*arg, &atom_identifiers, &arguments); + if let SExp::Atom(_, n) = new_arg.borrow() { atom_identifiers.push(n.clone()); } arguments.push(new_arg); @@ -604,27 +554,15 @@ impl CollectProgramStructure { let body_vals = self.body_forms.clone(); for b in body_vals.iter() { - let new_form = self.new_bodyform( - *b, - &atom_identifiers, - &constants, - &arguments, - &body_forms - ); + let new_form = + self.new_bodyform(*b, &atom_identifiers, &constants, &arguments, &body_forms); body_forms.push(new_form); } let mut helper_forms = Vec::new(); let helper_vals = self.helper_structures.clone(); - for (i,h) in helper_vals.iter().enumerate() { - let new_helper = self.new_helper( - i, - *h, - &constants, - &arguments, - &body_forms, - &helper_forms - ); + for (i, h) in helper_vals.iter().enumerate() { + let new_helper = self.new_helper(i, *h, &arguments, &body_forms, &helper_forms); helper_forms.push(new_helper); } @@ -633,34 +571,29 @@ impl CollectProgramStructure { &atom_identifiers, &constants, &arguments, - &body_forms + &body_forms, ); let use_arguments: u16 = self.get_choice(); - let arguments = - self.choose_with_default(&arguments, use_arguments, nil.clone()); + let arguments = self.choose_with_default(&arguments, use_arguments, nil.clone()); CompileForm { loc: loc.clone(), include_forms: Vec::new(), args: arguments.clone(), helpers: helper_forms, - exp: Rc::new(rewrite_identifiers( - arguments, - body.borrow() - )) + exp: Rc::new(rewrite_identifiers(arguments, body.borrow())), } } } impl Distribution for Standard { fn sample(&self, rng: &mut R) -> CollectProgramStructure { - let mut message_kind: u16 = MAX_ALTERNATIVE_CPS; let mut iters = 0; let mut cps: CollectProgramStructure = Default::default(); let mut have_body = false; loop { - let mut input_32: u32 = rng.gen(); + let input_32: u32 = rng.gen(); // Stop if zero. if input_32 == 0 { @@ -676,7 +609,6 @@ impl Distribution for Standard { for input in inputs.iter() { let input_type = input & 15; let input_val = input >> 4; - let mut have_body = false; // A new message type advances out of the prev phase. match input_type { @@ -698,7 +630,7 @@ impl Distribution for Standard { 1..7 => cps.body_forms.push(input_val), 8..10 => cps.arguments.push(input_val), 11 => cps.constants.push(input_val), - _ => cps.selectors.push(input_val) + _ => cps.selectors.push(input_val), } } } diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index 4a774d07e..18897530d 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -1,8 +1,8 @@ -#[cfg(any(test, feature="fuzzer"))] +#[cfg(any(test, feature = "fuzzer"))] use rand::distributions::Standard; -#[cfg(any(test, feature="fuzzer"))] +#[cfg(any(test, feature = "fuzzer"))] use rand::prelude::Distribution; -#[cfg(any(test, feature="fuzzer"))] +#[cfg(any(test, feature = "fuzzer"))] use rand::Rng; use std::borrow::Borrow; @@ -49,12 +49,12 @@ pub fn random_atom_name(rng: &mut R, min_size: usize) -> Vec(rng: &mut R) -> SExp { SExp::Atom(Srcloc::start("*rng*"), random_atom_name(rng, 1)) } -#[cfg(any(test, feature="fuzzer"))] +#[cfg(any(test, feature = "fuzzer"))] pub fn random_sexp(rng: &mut R, remaining: usize) -> SExp { if remaining < 2 { random_atom(rng) @@ -93,7 +93,7 @@ pub fn random_sexp(rng: &mut R, remaining: usize) -> SExp { } // Thanks: https://stackoverflow.com/questions/48490049/how-do-i-choose-a-random-value-from-an-enum -#[cfg(any(test, feature="fuzzer"))] +#[cfg(any(test, feature = "fuzzer"))] impl Distribution for Standard { fn sample(&self, rng: &mut R) -> SExp { random_sexp(rng, MAX_SEXP_COST) diff --git a/src/fuzzing/fuzzrng.rs b/src/fuzzing/fuzzrng.rs index db13ff592..0e1ea9390 100644 --- a/src/fuzzing/fuzzrng.rs +++ b/src/fuzzing/fuzzrng.rs @@ -1,15 +1,7 @@ use rand::prelude::*; use rand::Error; -use random_lfsr_256_galois::{InitRegisterPayload, LFSRGalois, LFSRGaloisBuilder}; - -// A pseudo RNG which uses a slice for all entropy. It iterates a given slice -// many times, scrambling the bits through an LFSR in subsequent passes so that -// the fuzzer maintains a relationship between the original input bits and the -// output with some predictability. -// -// This differs from BufRng in that it's not intended to be exhaustible since -// it's being used to generate extensible data structures. +// A pseudo RNG which uses a slice for all entropy. pub struct FuzzPseudoRng<'slice> { slice: &'slice [u8], progress: usize, diff --git a/src/lib.rs b/src/lib.rs index ab679eca1..c022619dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,7 @@ pub mod util; pub mod classic; pub mod compiler; -#[cfg(any(test, feature="fuzzer"))] +#[cfg(any(test, feature = "fuzzer"))] pub mod fuzzing; // Python impl diff --git a/test/proggen/src/main.rs b/test/proggen/src/main.rs index 5fdbb0a4c..752c12343 100644 --- a/test/proggen/src/main.rs +++ b/test/proggen/src/main.rs @@ -1,40 +1,31 @@ extern crate clvmr as clvm_rs; -use rand_chacha::ChaCha8Rng; use rand::prelude::*; use rand::SeedableRng; +use rand_chacha::ChaCha8Rng; -use sqlite; -use base64::{Engine as _, engine::general_purpose}; +use base64::{engine::general_purpose, Engine as _}; use std::borrow::Borrow; -use std::io::{self, BufRead, Write}; use std::rc::Rc; -use clvm_rs::allocator::Allocator; - use clvm_tools_rs::compiler::fuzzer::CollectProgramStructure; use clvm_tools_rs::compiler::sexp::SExp; use clvm_tools_rs::compiler::srcloc::Srcloc; -use clvm_tools_rs::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; -use clvm_tools_rs::fuzzing::make_random_u64_seed; use clvm_tools_rs::fuzzing::fuzzrng::FuzzPseudoRng; +use clvm_tools_rs::fuzzing::make_random_u64_seed; -fn do_program(db: &mut sqlite::Connection, dialect: Rc, buf: &[u8]) -> Rc { - let mut fpr = FuzzPseudoRng::new(&buf); +fn do_program(dialect: Rc, buf: &[u8]) -> Rc { + let mut fpr = FuzzPseudoRng::new(buf); let mut cps: CollectProgramStructure = fpr.gen(); let program = cps.to_program(); let pt = program.to_sexp(); - if let SExp::Cons(_,args,body) = pt.borrow() { + if let SExp::Cons(_, args, body) = pt.borrow() { let include_directive = Rc::new(SExp::Cons( pt.loc(), Rc::new(SExp::atom_from_string(pt.loc(), "include")), - Rc::new(SExp::Cons( - pt.loc(), - dialect, - Rc::new(SExp::Nil(pt.loc())) - )) + Rc::new(SExp::Cons(pt.loc(), dialect, Rc::new(SExp::Nil(pt.loc())))), )); Rc::new(SExp::Cons( pt.loc(), @@ -42,12 +33,8 @@ fn do_program(db: &mut sqlite::Connection, dialect: Rc, buf: &[u8]) -> Rc< Rc::new(SExp::Cons( pt.loc(), args.clone(), - Rc::new(SExp::Cons( - pt.loc(), - include_directive, - body.clone() - )) - )) + Rc::new(SExp::Cons(pt.loc(), include_directive, body.clone())), + )), )) } else { pt @@ -57,45 +44,54 @@ fn do_program(db: &mut sqlite::Connection, dialect: Rc, buf: &[u8]) -> Rc< fn write_prog_to_db(db: &mut sqlite::Connection, buf: &[u8], sexp: Rc) { let pts = sexp.to_string(); let encoded: String = general_purpose::STANDARD.encode(buf); - let mut stmt = db.prepare("insert or ignore into programs (b, t) values (?, ?)").expect("should work"); - let binds: &[sqlite::Value] = - &[sqlite::Value::String(encoded), sqlite::Value::String(pts)]; + let mut stmt = db + .prepare("insert or ignore into programs (b, t) values (?, ?)") + .expect("should work"); + let binds: &[sqlite::Value] = &[sqlite::Value::String(encoded), sqlite::Value::String(pts)]; stmt.bind(binds).unwrap(); stmt.next().expect("should work"); } fn main() { let mut rng = ChaCha8Rng::seed_from_u64(make_random_u64_seed()); - let mut buf = vec![0,0,0,0]; + let mut buf = vec![0, 0, 0, 0]; let mut conn = sqlite::open("prog.db").expect("db"); - if let Err(_) = conn.execute("create table if not exists programs (b text primary key, t text)") { + if conn + .execute("create table if not exists programs (b text primary key, t text)") + .is_err() + { eprintln!("failed to create db"); return; } - let this_len = buf.len(); let loc = Srcloc::start("*rng*"); let dialect = Rc::new(SExp::atom_from_string(loc, "*standard-cl-21*")); - let sexp = do_program(&mut conn, dialect.clone(), &buf); + let sexp = do_program(dialect.clone(), &buf); write_prog_to_db(&mut conn, &buf, sexp); - for p in 0..200000 { + for _ in 0..10000 { // Read a random row. { - let mut stmt = conn.prepare("SELECT b as b FROM programs ORDER BY RANDOM() LIMIT 1;").expect("should have selectable stuff"); + let mut stmt = conn + .prepare("SELECT b as b FROM programs ORDER BY RANDOM() LIMIT 1;") + .expect("should have selectable stuff"); if let Ok(sqlite::State::Row) = stmt.next() { - let this_buf_repr = stmt.read::("b").expect("should have the right column"); - buf = general_purpose::STANDARD.decode(this_buf_repr).expect("should exist"); + let this_buf_repr = stmt + .read::("b") + .expect("should have the right column"); + buf = general_purpose::STANDARD + .decode(this_buf_repr) + .expect("should exist"); } } - let mut next_byte = rng.gen_range(0..=buf.len()); + let next_byte = rng.gen_range(0..=buf.len()); if next_byte >= buf.len() - 3 { - for i in 0..4 { + for _ in 0..4 { buf.push(rng.gen()); } } else { @@ -103,7 +99,7 @@ fn main() { buf[next_byte + i] ^= rng.gen::(); } } - let sexp = do_program(&mut conn, dialect.clone(), &buf); + let sexp = do_program(dialect.clone(), &buf); eprintln!("{}", sexp); write_prog_to_db(&mut conn, &buf, sexp); } From bfb567e1445949966eaf3526be83d8b9bd0005d6 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Jan 2023 09:18:50 -0800 Subject: [PATCH 08/21] Fix range --- src/compiler/fuzzer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index bb452210a..c4ff9d42f 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -209,7 +209,7 @@ impl CollectProgramStructure { match c & 3 { 0..1 => { let raw_number = c & 0x3fff; - let bigint = (raw_number - 0x2000).to_bigint().unwrap(); + let bigint = ((raw_number as i32) - 0x2000).to_bigint().unwrap(); Rc::new(SExp::Integer(loc.clone(), bigint)) } 2 => { From c96abbb454c89f596f0bb3b6159978a60acae9e1 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Jan 2023 09:47:02 -0800 Subject: [PATCH 09/21] Commentary --- src/compiler/fuzzer.rs | 109 ++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 44 deletions(-) diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index c4ff9d42f..99e134200 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -33,56 +33,61 @@ const BINDING_NAME_MIN: usize = 3; const MAX_FORMS_CPS: usize = 512; const MAX_HELPER_KIND_CPS: u16 = 3; -#[derive(Debug, Clone)] -pub struct FuzzBinding { - pub name: Vec, - pub expr: FuzzOperation, -} - -/* - * Bitstream randomness -> - * - * Our goal is to devise a format where adding one to the stream yields a - * usefully different program. - * - * That means that at the left end of the we want more consequential information - * followed by less and less consequential information. - * - * The last bits should be constants, next to last select among alternative - * objects of the same time first the program structure, then more details. - * - * It'd be nice to have the stream start with the number of objects of each - * type but that'd make simple increments make big changes. I think it's better - * to have each new object be introduced via an increment on the right most byte. - * - * So we read the data as messages, where we accept a message if its priority is - * the current or lower priority, and end if it's higher. - * - * So we must read a set of messages: - * - * Structures (helper) -> Structure (body) -> Arguments -> Selectors -> Constants - * Where Structures contains - * (Constant | Function | Macro | Main) - * (quote | arg | if | mult | sub | sha256 | let | call) - * Arguments -> (cons | @ form | atom | nil) - * Selectors -> choose nth - * Constants -> (cons | hex+ | int | nil) - * - * Each 16 bits is a message. - * - * The low 3 bits of each word defines the message type, with types 6 and 7 - * currently ignored. - * For each, the other 13 bits are taken as the payload. - */ - +// +// Bitstream based randomness -> +// +// Our goal is to devise a format where adding one to the stream yields a +// usefully different program. +// +// That means that at the left end of the we want more consequential information +// followed by less and less consequential information. +// +// The last bits should be constants, next to last select among alternative +// objects of the same time first the program structure, then more details. +// +// It'd be nice to have the stream start with the number of objects of each +// type but that'd make simple increments make big changes. I think it's better +// to have each new object be introduced via an increment on the right most byte. +// +// So we must read a set of messages. Each message is 32 bits as a pair of +// 16 bit values. If the whole message is 0, then we stop reading. +// +// This is useful for scenarios like fuzzing where a specific, limited pattern +// is provided and we generate only based on that pattern. The messages are +// ordered lowest to highest in complexity and each message adds one piece of +// information. Since each type of form is generated separately, a correct +// program can be synthesized from any number (even 0) of accumulated messages. +// +// Each 16 bit value goes into one of 5 bins: +// +// Structures (helper) -> Structure (body) -> Arguments -> Constants -> Choices +// +// The payload of each is used to contain one of the choices needed downstream +// but others are teken from the choices bin, which is treated as a circular list +// of choice values we can use. +// +// Other than the helpers and choices, each of the structure types builds as an +// acyclic graph on its own list, accumulating larger structures as it goes, which +// are available as choices elsewhere. +// +// With constants generated, it generates body forms and with arguments generated +// it generates helpers and the whole program. +// #[derive(Clone, Debug, Default)] pub struct CollectProgramStructure { + // defmacro, defun, defconstant etc helper_structures: Vec, + // if (- ...) (sha256 ...) (let ...) etc body_forms: Vec, + // defining the argument shape for functions arguments: Vec, - selectors: Vec, + // constructs constants. constants: Vec, + // store of choices for filling out trees + selectors: Vec, + // current selector choice: usize, + // message representing the main expression main: u16, } @@ -296,7 +301,6 @@ impl CollectProgramStructure { let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); - // (quote | arg | if | mult | sub | sha256 | let | call) match b & 15 { 0 => { let choice_of_const = b >> 4; @@ -587,6 +591,8 @@ impl CollectProgramStructure { } } +// CollectProgramStructure becomes populated by a constrained set of bits. +// Use to_program to generate a CompileForm. impl Distribution for Standard { fn sample(&self, rng: &mut R) -> CollectProgramStructure { let mut iters = 0; @@ -644,8 +650,23 @@ impl Distribution for Standard { } } +// +// Random program generator for a continuous RNG. +// Assumes there are unlimited bits available and tries to provide a wide +// diversity of generated programs that have a high probability of processing +// inputs in interesting ways. Good for checking what code was generated +// since it comes with an interpreter for the abstract meaning of what was +// generated. +// // We don't actually need all operators here, just a good selection with // semantics that are distinguishable. +// +#[derive(Debug, Clone)] +pub struct FuzzBinding { + pub name: Vec, + pub expr: FuzzOperation, +} + #[derive(Debug, Clone)] pub enum FuzzOperation { Argref(usize), From 4376cb1eaa6035434167a9ac3e0a9fab59150647 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Jan 2023 09:51:34 -0800 Subject: [PATCH 10/21] Decide to only pull in CollectProgramStructure to make the diff smaller --- src/compiler/codegen.rs | 2 +- src/compiler/fuzzer.rs | 788 +--------------------------------------- src/compiler/sexp.rs | 14 +- 3 files changed, 11 insertions(+), 793 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 46ea07ff3..c81cfd826 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -113,7 +113,7 @@ fn compute_env_shape(l: Srcloc, args: Rc, helpers: &[HelperForm]) -> SExp SExp::Cons(l, Rc::new(car), cdr) } -pub fn create_name_lookup_( +fn create_name_lookup_( l: Srcloc, name: &[u8], env: Rc, diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index 99e134200..4b784326d 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -1,35 +1,20 @@ -use num_bigint::{BigInt, ToBigInt}; +use num_bigint::ToBigInt; use rand::distributions::Standard; use rand::prelude::*; use rand::Rng; use std::borrow::Borrow; -use std::cmp::max; use std::rc::Rc; -use crate::classic::clvm::__type_compatibility__::{bi_one, bi_zero}; -use crate::compiler::clvm::truthy; -use crate::compiler::codegen::create_name_lookup_; +use crate::classic::clvm::__type_compatibility__::bi_one; use crate::compiler::comptypes::{ Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, HelperForm, LetData, LetFormKind, }; -use crate::compiler::sexp::{enlist, SExp}; - -use crate::compiler::sexp::{random_atom_name, random_sexp}; - -use crate::classic::clvm::__type_compatibility__::{sha256, Bytes, BytesFromType, Stream}; -use crate::classic::clvm::casts::bigint_to_bytes_clvm; -use crate::compiler::runtypes::RunFailure; +use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; -use crate::util::Number; - -const MIN_ARGLIST: usize = 3; -const MAX_STEPS: usize = 1000; pub const MAX_LIST_BOUND: usize = 3; -const CURRENT_DIALECT: u32 = 21; -const BINDING_NAME_MIN: usize = 3; const MAX_FORMS_CPS: usize = 512; const MAX_HELPER_KIND_CPS: u16 = 3; @@ -649,770 +634,3 @@ impl Distribution for Standard { cps } } - -// -// Random program generator for a continuous RNG. -// Assumes there are unlimited bits available and tries to provide a wide -// diversity of generated programs that have a high probability of processing -// inputs in interesting ways. Good for checking what code was generated -// since it comes with an interpreter for the abstract meaning of what was -// generated. -// -// We don't actually need all operators here, just a good selection with -// semantics that are distinguishable. -// -#[derive(Debug, Clone)] -pub struct FuzzBinding { - pub name: Vec, - pub expr: FuzzOperation, -} - -#[derive(Debug, Clone)] -pub enum FuzzOperation { - Argref(usize), - Quote(SExp), - If(Rc, Rc, Rc), - Multiply(Rc, Rc), - Sub(Rc, Rc), - Sha256(Vec), - Let(Vec, Rc), - Call(u8, Vec), -} - -#[derive(Debug, Clone)] -pub enum ArgListType { - ProperList(u8), - Structure(SExp), -} - -#[derive(Debug, Clone)] -pub struct FuzzFunction { - pub inline: bool, - pub number: u8, - pub args: ArgListType, - pub body: FuzzOperation, -} - -#[derive(Debug, Clone)] -pub struct FuzzProgram { - pub args: ArgListType, - pub functions: Vec, - pub body: FuzzOperation, -} - -#[derive(Debug, Clone)] -pub struct FuzzOldProgram { - pub program: FuzzProgram, -} - -fn atom_list(sexp: &SExp) -> Vec> { - match sexp { - SExp::Nil(_) => vec![], - SExp::Atom(_, v) => { - if v.is_empty() { - vec![] - } else { - vec![v.clone()] - } - } - SExp::QuotedString(_, _, _) => vec![], - SExp::Integer(_, _) => vec![], - SExp::Cons(_, a, b) => { - let mut a_vec = atom_list(a.borrow()); - let b_vec = atom_list(b.borrow()); - for b_item in b_vec.iter() { - a_vec.push(b_item.clone()); - } - a_vec - } - } -} - -fn select_argument( - num: usize, - fun: &FuzzProgram, - bindings: &[Vec], -) -> (SExp, Option) { - let args_sexp = fun.args.to_sexp(); - let select_group = (num >> 8) % (bindings.len() + 1); - if select_group == bindings.len() { - // Select from arguments - let arg_list = atom_list(&args_sexp); - let nil = SExp::Nil(args_sexp.loc()); - if arg_list.is_empty() { - (nil.clone(), Some(FuzzOperation::Quote(nil))) - } else { - let selected_arg = arg_list[num & 0xff % arg_list.len()].clone(); - (SExp::Atom(args_sexp.loc(), selected_arg), None) - } - } else { - // Select a binding group using the second byte, - let group = &bindings[select_group]; - let select_binding = (num & 0xff) % group.len(); - let selected_binding = &group[select_binding]; - // Select a binding using the first byte. - ( - SExp::Atom(args_sexp.loc(), selected_binding.name.clone()), - Some(selected_binding.expr.clone()), - ) - } -} - -fn select_call(num: u8, prog: &FuzzProgram) -> (String, FuzzFunction) { - if prog.functions.len() == 0 { - panic!("we make programs with at least one function"); - } - let selected_num = num % prog.functions.len() as u8; - let selected = &prog.functions[selected_num as usize]; - (format!("fun_{}", selected_num), selected.clone()) -} - -fn make_operator(op: String, args: Vec) -> SExp { - let loc = Srcloc::start(&"*rng*".to_string()); - let mut result = SExp::Nil(loc.clone()); - - for i_reverse in 0..args.len() { - let i = args.len() - i_reverse - 1; - result = SExp::Cons(loc.clone(), Rc::new(args[i].clone()), Rc::new(result)); - } - - SExp::Cons( - loc.clone(), - Rc::new(SExp::atom_from_string(loc.clone(), &op)), - Rc::new(result), - ) -} - -fn distribute_args( - a: ArgListType, - fun: &FuzzProgram, - bindings: &[Vec], - arginputs: &Vec, - spine: bool, - argn: u8, -) -> (u8, SExp) { - let loc = Srcloc::start(&"*rng*".to_string()); - match a { - ArgListType::ProperList(0) => (argn, SExp::Nil(loc.clone())), - ArgListType::ProperList(n) => { - let rest_result = distribute_args( - ArgListType::ProperList(n - 1), - fun, - bindings, - arginputs, - spine, - argn + 1, - ); - ( - rest_result.0, - SExp::Cons( - loc.clone(), - Rc::new(arginputs[argn as usize].clone()), - Rc::new(rest_result.1), - ), - ) - } - ArgListType::Structure(SExp::Nil(l)) => (argn, SExp::Nil(l.clone())), - ArgListType::Structure(SExp::Cons(l, a, b)) => { - let a_borrow: &SExp = a.borrow(); - let b_borrow: &SExp = b.borrow(); - let first_res = distribute_args( - ArgListType::Structure(a_borrow.clone()), - fun, - bindings, - arginputs, - false, - argn, - ); - let rest_res = distribute_args( - ArgListType::Structure(b_borrow.clone()), - fun, - bindings, - arginputs, - spine, - argn + first_res.0, - ); - let res = if spine { - SExp::Cons(l.clone(), Rc::new(first_res.1), Rc::new(rest_res.1)) - } else { - make_operator("c".to_string(), vec![first_res.1, rest_res.1]) - }; - (rest_res.0, res) - } - ArgListType::Structure(_) => { - if spine { - distribute_args( - ArgListType::ProperList(1), - fun, - bindings, - arginputs, - spine, - argn, - ) - } else { - (argn + 1_u8, arginputs[argn as usize].clone()) - } - } - } -} - -fn random_args(rng: &mut R, loc: Srcloc, a: ArgListType) -> SExp { - match a { - ArgListType::ProperList(0) => SExp::Nil(loc.clone()), - ArgListType::ProperList(n) => { - let loc = Srcloc::start("*rng*"); - enlist(loc, (0..n).map(|_| Rc::new(rng.gen())).collect()) - } - ArgListType::Structure(SExp::Nil(l)) => SExp::Nil(l.clone()), - ArgListType::Structure(SExp::Cons(_, a, b)) => { - let borrowed_a: &SExp = a.borrow(); - let borrowed_b: &SExp = b.borrow(); - SExp::Cons( - loc.clone(), - Rc::new(random_args( - rng, - loc.clone(), - ArgListType::Structure(borrowed_a.clone()), - )), - Rc::new(random_args( - rng, - loc.clone(), - ArgListType::Structure(borrowed_b.clone()), - )), - ) - } - ArgListType::Structure(_) => { - let random_64: u64 = rng.gen(); - SExp::Integer(loc.clone(), random_64.to_bigint().unwrap()) - } - } -} - -impl FuzzOperation { - pub fn to_sexp(&self, fun: &FuzzProgram, bindings: &[Vec]) -> SExp { - let loc = Srcloc::start(&"*rng*".to_string()); - match self { - FuzzOperation::Argref(argument_num) => { - let argument = select_argument(*argument_num as usize, fun, &bindings); - argument.0 - } - FuzzOperation::Quote(s) => SExp::Cons( - loc.clone(), - Rc::new(SExp::atom_from_string(loc.clone(), &"q".to_string())), - Rc::new(s.clone()), - ), - FuzzOperation::If(cond, ct, cf) => make_operator( - "if".to_string(), - vec![ - cond.to_sexp(fun, bindings), - ct.to_sexp(fun, bindings), - cf.to_sexp(fun, bindings), - ], - ), - FuzzOperation::Multiply(a, b) => make_operator( - "*".to_string(), - vec![a.to_sexp(fun, bindings), b.to_sexp(fun, bindings)], - ), - FuzzOperation::Sub(a, b) => make_operator( - "-".to_string(), - vec![a.to_sexp(fun, bindings), b.to_sexp(fun, bindings)], - ), - FuzzOperation::Sha256(ents) => make_operator( - "sha256".to_string(), - ents.iter().map(|x| x.to_sexp(fun, bindings)).collect(), - ), - FuzzOperation::Let(our_bindings, body) => { - let loc = Srcloc::start(&"*rng*".to_string()); - let mut bindings_done = SExp::Nil(loc.clone()); - - for b in our_bindings.iter().rev() { - bindings_done = SExp::Cons( - loc.clone(), - Rc::new(SExp::Cons( - loc.clone(), - Rc::new(SExp::Atom(loc.clone(), b.name.clone())), - Rc::new(SExp::Cons( - loc.clone(), - Rc::new(b.expr.to_sexp(fun, bindings)), - Rc::new(SExp::Nil(loc.clone())), - )), - )), - Rc::new(bindings_done), - ); - } - - let mut inner_bindings = bindings.to_vec(); - inner_bindings.push(our_bindings.clone()); - - make_operator( - "let".to_string(), - vec![bindings_done, body.to_sexp(fun, &inner_bindings)], - ) - } - FuzzOperation::Call(selection, args) => { - let loc = Srcloc::start(&"*rng*".to_string()); - let called_fun = select_call(*selection, fun); - let mut reified_args = Vec::new(); - for a in args.iter() { - reified_args.push(a.to_sexp(fun, bindings)); - } - let args = distribute_args( - called_fun.1.args.clone(), - fun, - bindings, - &reified_args, - true, - 0, - ); - SExp::Cons( - loc.clone(), - Rc::new(SExp::atom_from_string(loc.clone(), &called_fun.0)), - Rc::new(args.1), - ) - } - } - } -} - -fn make_random_call(rng: &mut R, dialect: u32, remaining: usize) -> FuzzOperation { - FuzzOperation::Call( - rng.gen(), - (0..=255) - .map(|_| random_operation(rng, dialect, remaining - 1)) - .collect(), - ) -} - -// FuzzOperation is potentially infinite so we'll limit the depth to something -// sensible. -fn random_operation(rng: &mut R, dialect: u32, remaining: usize) -> FuzzOperation { - if remaining < 2 { - FuzzOperation::Quote(random_sexp(rng, remaining)) - } else { - let op_bound = if dialect >= 21 { 7 } else { 6 }; - let alternative: usize = rng.gen_range(0..=op_bound); - match alternative { - 0 => FuzzOperation::Argref(rng.gen()), - 1 => FuzzOperation::If( - Rc::new(random_operation(rng, dialect, remaining - 1)), - Rc::new(random_operation(rng, dialect, remaining - 1)), - Rc::new(random_operation(rng, dialect, remaining - 1)), - ), - 2 => FuzzOperation::Multiply( - Rc::new(random_operation(rng, dialect, remaining - 1)), - Rc::new(random_operation(rng, dialect, remaining - 1)), - ), - 3 => FuzzOperation::Sub( - Rc::new(random_operation(rng, dialect, remaining - 1)), - Rc::new(random_operation(rng, dialect, remaining - 1)), - ), - 4 => { - let bound: usize = rng.gen_range(0..=MAX_LIST_BOUND); - FuzzOperation::Sha256( - (0..=bound) - .map(|_| random_operation(rng, dialect, remaining - 1)) - .collect(), - ) - } - 5 => make_random_call(rng, dialect, remaining - 1), - 6 => FuzzOperation::Quote(random_sexp(rng, remaining)), - _ => { - let bound: usize = rng.gen_range(1..=5); - let new_bindings: Vec = (1..=bound) - .map(|_| FuzzBinding { - name: random_atom_name(rng, BINDING_NAME_MIN), - expr: random_operation(rng, dialect, remaining - 1), - }) - .collect(); - FuzzOperation::Let( - new_bindings, - Rc::new(random_operation(rng, dialect, remaining - 1)), - ) - } - } - } -} - -impl Distribution for Standard { - fn sample(&self, rng: &mut R) -> FuzzOperation { - random_operation(rng, 22, MAX_LIST_BOUND) - } -} - -fn min_arglist(remaining: usize) -> usize { - max(remaining, MIN_ARGLIST) -} - -fn random_arglist_cons(rng: &mut R, loc: &Srcloc, remaining: usize) -> SExp { - if rng.gen() || remaining < 1 { - SExp::Atom(loc.clone(), random_atom_name(rng, 2)) - } else { - let left = random_arglist_cons(rng, loc, remaining - 1); - let right = random_arglist_cons(rng, loc, remaining - 1); - SExp::Cons(loc.clone(), Rc::new(left), Rc::new(right)) - } -} - -fn random_arglist(rng: &mut R, remaining: usize) -> ArgListType { - let loc = Srcloc::start("*arglist*"); - let truncated_len = (remaining % 255) as u8; - if rng.gen() { - ArgListType::ProperList(rng.gen_range(0..=truncated_len)) - } else { - let mut structure = SExp::Nil(loc.clone()); - for _ in 0..=min_arglist(truncated_len as usize) { - structure = SExp::Cons( - loc.clone(), - Rc::new(random_arglist_cons(rng, &loc, remaining - 1)), - Rc::new(structure), - ); - } - - ArgListType::Structure(structure) - } -} - -impl Distribution for Standard { - fn sample(&self, rng: &mut R) -> ArgListType { - random_arglist(rng, MAX_LIST_BOUND) - } -} - -impl ArgListType { - pub fn random_args(&self, rng: &mut R) -> SExp { - let loc = Srcloc::start(&"*rng*".to_string()); - match self { - ArgListType::ProperList(n) => { - let mut args = SExp::Nil(loc.clone()); - for _ in 0..*n { - let random_bytes: Vec = (0..=MAX_LIST_BOUND).map(|_| rng.gen()).collect(); - args = SExp::Cons( - args.loc(), - Rc::new(SExp::atom_from_vec(loc.clone(), &random_bytes)), - Rc::new(args.clone()), - ); - } - args - } - ArgListType::Structure(SExp::Nil(l)) => SExp::Nil(l.clone()), - ArgListType::Structure(SExp::Cons(l, a, b)) => { - let aborrow: &SExp = a.borrow(); - let bborrow: &SExp = b.borrow(); - let aclone = aborrow.clone(); - let bclone = bborrow.clone(); - let arg_a = ArgListType::Structure(aclone).random_args(rng); - let arg_b = ArgListType::Structure(bclone).random_args(rng); - SExp::Cons(l.clone(), Rc::new(arg_a), Rc::new(arg_b)) - } - ArgListType::Structure(_) => rng.gen(), - } - } - - fn to_sexp(&self) -> SExp { - let loc = Srcloc::start(&"*rng*".to_string()); - match self { - ArgListType::ProperList(n) => { - let mut args = SExp::Nil(loc.clone()); - for i_reverse in 0..*n { - let i = n - i_reverse; - args = SExp::Cons( - args.loc(), - Rc::new(SExp::atom_from_string(loc.clone(), &format!("arg_{}", i))), - Rc::new(args.clone()), - ); - } - args - } - ArgListType::Structure(s) => s.clone(), - } - } -} - -fn random_function(rng: &mut R, dialect: u32, remaining: usize) -> FuzzFunction { - FuzzFunction { - inline: rng.gen(), - number: 0, - args: random_arglist(rng, remaining - 1), - body: random_operation(rng, dialect, remaining - 1), - } -} - -impl Distribution for Standard { - fn sample(&self, rng: &mut R) -> FuzzFunction { - random_function(rng, CURRENT_DIALECT, MAX_LIST_BOUND) - } -} - -impl FuzzFunction { - fn to_sexp(&self, fun: &FuzzProgram) -> SExp { - let fuzzloc = Srcloc::start(&"*fuzz*".to_string()); - let initial_atom = if self.inline { - SExp::atom_from_string(fuzzloc.clone(), &"defun-inline".to_string()) - } else { - SExp::atom_from_string(fuzzloc.clone(), &"defun".to_string()) - }; - let name_atom = SExp::atom_from_string(fuzzloc.clone(), &format!("fun_{}", self.number)); - let args_sexp = self.args.to_sexp(); - let body_sexp = self.body.to_sexp(&self.to_program(fun), &Vec::new()); - SExp::Cons( - fuzzloc.clone(), - Rc::new(initial_atom), - Rc::new(SExp::Cons( - fuzzloc.clone(), - Rc::new(name_atom), - Rc::new(SExp::Cons( - fuzzloc.clone(), - Rc::new(args_sexp), - Rc::new(SExp::Cons( - fuzzloc.clone(), - Rc::new(body_sexp), - Rc::new(SExp::Nil(fuzzloc.clone())), - )), - )), - )), - ) - } - - fn to_program(&self, parent: &FuzzProgram) -> FuzzProgram { - FuzzProgram { - args: self.args.clone(), - functions: parent.functions.clone(), - body: self.body.clone(), - } - } -} - -/* - * Produce chialisp frontend code with an expected result - */ -fn random_program(rng: &mut R, dialect: u32, remaining: usize) -> FuzzProgram { - let num_funs = rng.gen_range(1..=MAX_LIST_BOUND); - let funs: Vec = (1..=num_funs) - .map(|_| random_function(rng, dialect, remaining - 1)) - .enumerate() - .map(|(i, f): (usize, FuzzFunction)| { - let mut fcopy = f.clone(); - fcopy.number = i as u8; - fcopy - }) - .collect(); - FuzzProgram { - args: random_arglist(rng, remaining), - functions: funs, - body: random_operation(rng, dialect, remaining), - } -} - -impl Distribution for Standard { - fn sample(&self, rng: &mut R) -> FuzzProgram { - random_program(rng, CURRENT_DIALECT, MAX_LIST_BOUND) - } -} - -fn evaluate_to_numbers( - prog: &FuzzProgram, - args: &SExp, - bindings: &[Vec], - a: &FuzzOperation, - b: &FuzzOperation, - steps: usize, -) -> Result<(BigInt, BigInt), RunFailure> { - let a_val = interpret_program(prog, args, bindings, a, steps - 1)?; - let b_val = interpret_program(prog, args, bindings, b, steps - 1)?; - match (&a_val, &b_val) { - (SExp::Integer(_, a), SExp::Integer(_, b)) => Ok((a.clone(), b.clone())), - (SExp::Cons(l, _, _), _) => Err(RunFailure::RunErr( - l.clone(), - format!("*: expected atom got {}", a_val.to_string()), - )), - (_, SExp::Cons(l, _, _)) => Err(RunFailure::RunErr( - l.clone(), - format!("*: expected atom got {}", b_val.to_string()), - )), - (a, b) => { - let num_a = a - .get_number() - .map_err(|e| RunFailure::RunErr(a.loc(), e.1))?; - let num_b = b - .get_number() - .map_err(|e| RunFailure::RunErr(b.loc(), e.1))?; - Ok((num_a, num_b)) - } - } -} - -fn byte_vec_of_sexp(val: &SExp) -> Result, RunFailure> { - match val { - SExp::Nil(_) => Ok(Vec::new()), - SExp::Atom(_, a) => Ok(a.clone()), - SExp::QuotedString(_, _, s) => Ok(s.clone()), - SExp::Integer(_, i) => Ok(bigint_to_bytes_clvm(i).data().clone()), - _ => Err(RunFailure::RunErr( - val.loc(), - format!("attempt to convert {} to bytes", val.to_string()), - )), - } -} - -fn choose_path(path: Number, args: Rc) -> Result, RunFailure> { - if path == bi_one() { - Ok(args) - } else { - match args.borrow() { - SExp::Cons(_, a, b) => { - let odd = bi_one() & path.clone(); - if odd != bi_zero() { - choose_path(path >> 1, b.clone()) - } else { - choose_path(path >> 1, a.clone()) - } - } - _ => Err(RunFailure::RunErr(args.loc(), "path into atom".to_string())), - } - } -} - -fn interpret_program( - prog: &FuzzProgram, - args: &SExp, - bindings: &[Vec], - expr: &FuzzOperation, - steps: usize, -) -> Result { - if steps < 1 { - return Err(RunFailure::RunErr( - args.loc(), - "too many steps taken".to_string(), - )); - } - let loc = Srcloc::start(&"*interp*".to_string()); - match &expr { - FuzzOperation::Argref(n) => { - let (argname, run_expression) = select_argument(*n as usize, prog, bindings); - if let Some(to_run) = run_expression { - // Run binding code selected. - interpret_program(prog, args, bindings, &to_run, steps - 1) - } else { - // Select argument from env. - let argpath = create_name_lookup_( - args.loc(), - &argname.to_string().as_bytes(), - Rc::new(prog.args.to_sexp()), - Rc::new(prog.args.to_sexp()), - ) - .map_err(|e| RunFailure::RunErr(e.0.clone(), e.1.clone()))?; - let argval = choose_path(argpath.to_bigint().unwrap(), Rc::new(args.clone()))?; - let argval_borrow: &SExp = argval.borrow(); - interpret_program( - prog, - args, - bindings, - &FuzzOperation::Quote(argval_borrow.clone()), - steps - 1, - ) - } - } - FuzzOperation::Quote(exp) => Ok(exp.clone()), - FuzzOperation::If(cond, iftrue, iffalse) => { - let borrowed_cond: &FuzzOperation = cond.borrow(); - interpret_program(prog, args, bindings, borrowed_cond, steps - 1) - .map(|cond_res| truthy(Rc::new(cond_res))) - .and_then(|cond_res| { - if cond_res { - let borrowed_iftrue: &FuzzOperation = iftrue.borrow(); - interpret_program(prog, args, bindings, borrowed_iftrue, steps - 1) - } else { - let borrowed_iffalse: &FuzzOperation = iffalse.borrow(); - interpret_program(prog, args, bindings, borrowed_iffalse, steps - 1) - } - }) - } - FuzzOperation::Multiply(a, b) => { - let (a_val, b_val) = - evaluate_to_numbers(prog, args, bindings, a.borrow(), b.borrow(), steps - 1)?; - Ok(SExp::Integer(loc, a_val * b_val)) - } - FuzzOperation::Sub(a, b) => { - let (a_val, b_val) = - evaluate_to_numbers(prog, args, bindings, a.borrow(), b.borrow(), steps - 1)?; - Ok(SExp::Integer(loc, a_val - b_val)) - } - FuzzOperation::Sha256(lst) => { - let loc = Srcloc::start(&"*sha256*".to_string()); - let mut bytes_stream = Stream::new(None); - for elt in lst.iter() { - let output = interpret_program(prog, args, bindings, &elt, steps - 1)?; - let output_bytes = byte_vec_of_sexp(&output)?; - bytes_stream.write(Bytes::new(Some(BytesFromType::Raw(output_bytes)))); - } - Ok(SExp::Atom( - loc, - sha256(bytes_stream.get_value()).data().clone(), - )) - } - FuzzOperation::Let(new_bindings, body) => { - let mut total_bindings = bindings.to_vec(); - total_bindings.push(new_bindings.clone()); - interpret_program(prog, args, &total_bindings, body.borrow(), steps - 1) - } - FuzzOperation::Call(fun, call_args) => { - let called_fun = select_call(*fun, prog); - let mut reified_args = Vec::new(); - - // Interpret all arguments. - for a in call_args.iter() { - reified_args.push(interpret_program(prog, args, bindings, a, steps - 1)?); - } - - // Use reified arguments since we're assuming they're sexp. - let distributed_args = distribute_args( - called_fun.1.args.clone(), - prog, - bindings, - &reified_args, - true, - 0, - ); - interpret_program( - &called_fun.1.to_program(prog), - &distributed_args.1, - &Vec::new(), - &called_fun.1.body.clone(), - steps - 1, - ) - } - } -} - -impl FuzzProgram { - pub fn to_sexp(&self) -> SExp { - let mut body_vec = Vec::new(); - body_vec.push(self.args.to_sexp()); - for f in &self.functions { - body_vec.push(f.to_sexp(self)) - } - body_vec.push(self.body.to_sexp(self, &Vec::new())); - make_operator("mod".to_string(), body_vec) - } - - pub fn random_args(&self, rng: &mut R) -> SExp { - let srcloc = Srcloc::start(&"*args*".to_string()); - random_args(rng, srcloc, self.args.clone()) - } - - pub fn interpret(&self, args: SExp) -> Result { - interpret_program(self, &args, &Vec::new(), &self.body, MAX_STEPS) - } -} - -fn random_old_program(rng: &mut R, remaining: usize) -> FuzzOldProgram { - FuzzOldProgram { - program: random_program(rng, 0, remaining), - } -} - -impl Distribution for Standard { - fn sample(&self, rng: &mut R) -> FuzzOldProgram { - random_old_program(rng, MAX_LIST_BOUND) - } -} diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index 18897530d..d8ac5234c 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -1,8 +1,8 @@ -#[cfg(any(test, feature = "fuzzer"))] +#[cfg(test)] use rand::distributions::Standard; -#[cfg(any(test, feature = "fuzzer"))] +#[cfg(test)] use rand::prelude::Distribution; -#[cfg(any(test, feature = "fuzzer"))] +#[cfg(test)] use rand::Rng; use std::borrow::Borrow; @@ -32,7 +32,7 @@ pub enum SExp { Atom(Srcloc, Vec), } -#[cfg(any(test, feature = "fuzzer"))] +#[cfg(test)] pub fn random_atom_name(rng: &mut R, min_size: usize) -> Vec { let mut bytevec: Vec = Vec::new(); let mut len = 0; @@ -49,12 +49,12 @@ pub fn random_atom_name(rng: &mut R, min_size: usize) -> Vec(rng: &mut R) -> SExp { SExp::Atom(Srcloc::start("*rng*"), random_atom_name(rng, 1)) } -#[cfg(any(test, feature = "fuzzer"))] +#[cfg(test)] pub fn random_sexp(rng: &mut R, remaining: usize) -> SExp { if remaining < 2 { random_atom(rng) @@ -93,7 +93,7 @@ pub fn random_sexp(rng: &mut R, remaining: usize) -> SExp { } // Thanks: https://stackoverflow.com/questions/48490049/how-do-i-choose-a-random-value-from-an-enum -#[cfg(any(test, feature = "fuzzer"))] +#[cfg(test)] impl Distribution for Standard { fn sample(&self, rng: &mut R) -> SExp { random_sexp(rng, MAX_SEXP_COST) From 0ffa477f603c50e1575c5c0a0bd696534629bdf9 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Jan 2023 09:55:46 -0800 Subject: [PATCH 11/21] Cut down a bit --- src/fuzzing/mod.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/fuzzing/mod.rs b/src/fuzzing/mod.rs index f2a942af1..e32a257bf 100644 --- a/src/fuzzing/mod.rs +++ b/src/fuzzing/mod.rs @@ -1,19 +1,11 @@ -use num_bigint::ToBigInt; -use num_traits::ToPrimitive; use rand::prelude::*; use rand_chacha::ChaCha8Rng; -use crate::compiler::sexp::random_atom_name; -use crate::util::number_from_u8; - pub mod fuzzrng; // Note: Used for testing out aspects of the generated programs, since i've // funneled in the bits from fuzzing to an rng interface. pub fn make_random_u64_seed() -> u64 { let mut rng = ChaCha8Rng::from_entropy(); - let random_seed = random_atom_name(&mut rng, 10); - let random_seed_as_bigint = - number_from_u8(&random_seed) & 0xffffffffffff_u64.to_bigint().unwrap(); - random_seed_as_bigint.to_u64().unwrap() + rng.gen() } From a81553ae7f2209a8dd880a1e2e65dd54edb7fb43 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Jan 2023 10:12:10 -0800 Subject: [PATCH 12/21] Change from range match form --- src/compiler/fuzzer.rs | 364 ++++++++++++++++++++--------------------- src/lib.rs | 2 - 2 files changed, 177 insertions(+), 189 deletions(-) diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index 4b784326d..87a134aa2 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -196,34 +196,30 @@ impl CollectProgramStructure { fn new_constant(&mut self, c: u16, constants: &[Rc]) -> Rc { let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); - match c & 3 { - 0..1 => { - let raw_number = c & 0x3fff; - let bigint = ((raw_number as i32) - 0x2000).to_bigint().unwrap(); - Rc::new(SExp::Integer(loc.clone(), bigint)) - } - 2 => { - // Hex+ - // If the last item is also a number, this number concatenates - // them. - let new_byte = ((c >> 2) & 0xff) as u8; - if !constants.is_empty() { - if let SExp::Atom(l, n) = constants[constants.len() - 1].borrow() { - let mut new_atom_content = n.to_vec(); - new_atom_content.push(new_byte); - return Rc::new(SExp::Atom(l.clone(), new_atom_content)); - } + if c < 2 { + let raw_number = c & 0x3fff; + let bigint = ((raw_number as i32) - 0x2000).to_bigint().unwrap(); + Rc::new(SExp::Integer(loc.clone(), bigint)) + } else if c == 2 { + // Hex+ + // If the last item is also a number, this number concatenates + // them. + let new_byte = ((c >> 2) & 0xff) as u8; + if !constants.is_empty() { + if let SExp::Atom(l, n) = constants[constants.len() - 1].borrow() { + let mut new_atom_content = n.to_vec(); + new_atom_content.push(new_byte); + return Rc::new(SExp::Atom(l.clone(), new_atom_content)); } - Rc::new(SExp::Atom(loc.clone(), vec![new_byte])) - } - _ => { - // Cons. - let choice_of_a = c >> 2; - let choice_of_b: u16 = self.get_choice(); - let a = self.choose_with_default(&constants, choice_of_a, nil.clone()); - let b = self.choose_with_default(&constants, choice_of_b, nil.clone()); - Rc::new(SExp::Cons(loc.clone(), a, b)) } + Rc::new(SExp::Atom(loc.clone(), vec![new_byte])) + } else { + // Cons. + let choice_of_a = c >> 2; + let choice_of_b: u16 = self.get_choice(); + let a = self.choose_with_default(&constants, choice_of_a, nil.clone()); + let b = self.choose_with_default(&constants, choice_of_b, nil.clone()); + Rc::new(SExp::Cons(loc.clone(), a, b)) } } @@ -286,58 +282,54 @@ impl CollectProgramStructure { let loc = Srcloc::start("*rng*"); let nil = Rc::new(SExp::Nil(loc.clone())); let body_nil = Rc::new(BodyForm::Quoted(SExp::Nil(loc.clone()))); - match b & 15 { - 0 => { - let choice_of_const = b >> 4; - let constant = self.choose_with_default(&constants, choice_of_const, nil.clone()); - let constant_borrowed: &SExp = constant.borrow(); - Rc::new(BodyForm::Quoted(constant_borrowed.clone())) - } - 1..6 => { - let choice_of_arg = b >> 3; - let arg = self.choose_with_default(&atom_identifiers, choice_of_arg, vec![b'X']); - Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), arg))) - } - 7 => { - let choice_of_cond = b >> 3; - let choice_of_then: u16 = self.get_choice(); - let choice_of_else: u16 = self.get_choice(); - let use_cond = - self.choose_with_default(&body_forms, choice_of_cond, body_nil.clone()); - let use_then = - self.choose_with_default(&body_forms, choice_of_then, body_nil.clone()); - let use_else = - self.choose_with_default(&body_forms, choice_of_else, body_nil.clone()); - Rc::new(BodyForm::Call( - loc.clone(), - vec![ - Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), "if"))), - use_cond, - use_then, - use_else, - ], - )) - } - 8 => { - let choice_of_a = b >> 3; - let choice_of_b: u16 = self.get_choice(); - let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); - let use_b = self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); - Rc::new(BodyForm::Call( - loc.clone(), - vec![ - Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![18]))), - use_a, - use_b, - ], - )) - } - 9 => { - let choice_of_a = b >> 3; - let choice_of_b: u16 = self.get_choice(); - let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); - let use_b = self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); - Rc::new(BodyForm::Call( + let selector = b & 15; + if selector == 0 { + let choice_of_const = b >> 4; + let constant = self.choose_with_default(&constants, choice_of_const, nil.clone()); + let constant_borrowed: &SExp = constant.borrow(); + Rc::new(BodyForm::Quoted(constant_borrowed.clone())) + } else if selector < 7 { + let choice_of_arg = b >> 3; + let arg = self.choose_with_default(&atom_identifiers, choice_of_arg, vec![b'X']); + Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), arg))) + } else if selector == 7 { + let choice_of_cond = b >> 3; + let choice_of_then: u16 = self.get_choice(); + let choice_of_else: u16 = self.get_choice(); + let use_cond = + self.choose_with_default(&body_forms, choice_of_cond, body_nil.clone()); + let use_then = + self.choose_with_default(&body_forms, choice_of_then, body_nil.clone()); + let use_else = + self.choose_with_default(&body_forms, choice_of_else, body_nil.clone()); + Rc::new(BodyForm::Call( + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::atom_from_string(loc.clone(), "if"))), + use_cond, + use_then, + use_else, + ], + )) + } else if selector == 8 { + let choice_of_a = b >> 3; + let choice_of_b: u16 = self.get_choice(); + let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); + let use_b = self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); + Rc::new(BodyForm::Call( + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![18]))), + use_a, + use_b, + ], + )) + } else if selector == 9 { + let choice_of_a = b >> 3; + let choice_of_b: u16 = self.get_choice(); + let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); + let use_b = self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); + Rc::new(BodyForm::Call( loc.clone(), vec![ Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![17]))), @@ -345,103 +337,99 @@ impl CollectProgramStructure { use_b, ], )) - } - 10 => { - let choice_of_a = b >> 3; - let choice_of_b: u16 = self.get_choice(); - let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); - let use_b = self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); - Rc::new(BodyForm::Call( - loc.clone(), - vec![ - Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![11]))), - use_a, - use_b, - ], - )) - } - 11 => { - // Synthesize a let form. - let num_bindings = (b >> 3) & 3; - let kind = if (b >> 5) != 0 { - LetFormKind::Parallel - } else { - LetFormKind::Sequential - }; - let mut collected_names = Vec::new(); - let mut collected_bindings = Vec::new(); - for _ in 0..=num_bindings { - let choice_of_name: u16 = self.get_choice(); - let choice_of_body = b >> 6; - let arg_atom = - atom_identifiers[choice_of_name as usize % atom_identifiers.len()].clone(); - if collected_names.contains(&arg_atom) { - break; - } - - let body = - self.choose_with_default(&body_forms, choice_of_body, body_nil.clone()); - - collected_names.push(arg_atom.clone()); - collected_bindings.push(Rc::new(Binding { - loc: loc.clone(), - nl: loc.clone(), - name: arg_atom, - body: body, - })); + } else if selector == 10 { + let choice_of_a = b >> 3; + let choice_of_b: u16 = self.get_choice(); + let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); + let use_b = self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); + Rc::new(BodyForm::Call( + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![11]))), + use_a, + use_b, + ], + )) + } else if selector == 11 { + // Synthesize a let form. + let num_bindings = (b >> 3) & 3; + let kind = if (b >> 5) != 0 { + LetFormKind::Parallel + } else { + LetFormKind::Sequential + }; + let mut collected_names = Vec::new(); + let mut collected_bindings = Vec::new(); + for _ in 0..=num_bindings { + let choice_of_name: u16 = self.get_choice(); + let choice_of_body = b >> 6; + let arg_atom = + atom_identifiers[choice_of_name as usize % atom_identifiers.len()].clone(); + if collected_names.contains(&arg_atom) { + break; } - let body = self.choose_with_default(&body_forms, b >> 5, body_nil.clone()); + let body = + self.choose_with_default(&body_forms, choice_of_body, body_nil.clone()); - Rc::new(BodyForm::Let( - kind, - LetData { - loc: loc.clone(), - kw: None, - bindings: collected_bindings, - body: body, - }, - )) + collected_names.push(arg_atom.clone()); + collected_bindings.push(Rc::new(Binding { + loc: loc.clone(), + nl: loc.clone(), + name: arg_atom, + body: body, + })); } - _ => { - // Call - if self.helper_structures.is_empty() { - return body_nil.clone(); - } - let choice_of_helper = (b >> 3) as usize % self.helper_structures.len(); - let helper_spec = self.helper_structures - [choice_of_helper as usize % self.helper_structures.len()]; - let choice_of_arg = helper_spec >> 3; - let call_args = self.choose_with_default(&arguments, choice_of_arg, nil.clone()); - let mut arg_sites = Vec::new(); - self.isolate_arg_sites(&mut arg_sites, call_args); - let helper_name = format!("helper_{}", choice_of_helper); - if helper_spec & 3 == 0 { - // Reference constant - return Rc::new(BodyForm::Value(SExp::atom_from_string( - loc.clone(), - &helper_name, - ))); - } + let body = self.choose_with_default(&body_forms, b >> 5, body_nil.clone()); - // Reference callable - let mut call_args: Vec> = arg_sites - .iter() - .map(|_| { - let choice_of_expr: u16 = self.get_choice(); - self.choose_with_default(&body_forms, choice_of_expr, body_nil.clone()) - }) - .collect(); - call_args.insert( - 0, - Rc::new(BodyForm::Value(SExp::atom_from_string( - loc.clone(), - &helper_name, - ))), - ); - Rc::new(BodyForm::Call(loc.clone(), call_args)) + Rc::new(BodyForm::Let( + kind, + LetData { + loc: loc.clone(), + kw: None, + bindings: collected_bindings, + body: body, + }, + )) + } else { + // Call + if self.helper_structures.is_empty() { + return body_nil.clone(); + } + + let choice_of_helper = (b >> 3) as usize % self.helper_structures.len(); + let helper_spec = self.helper_structures + [choice_of_helper as usize % self.helper_structures.len()]; + let choice_of_arg = helper_spec >> 3; + let call_args = self.choose_with_default(&arguments, choice_of_arg, nil.clone()); + let mut arg_sites = Vec::new(); + self.isolate_arg_sites(&mut arg_sites, call_args); + let helper_name = format!("helper_{}", choice_of_helper); + if helper_spec & 3 == 0 { + // Reference constant + return Rc::new(BodyForm::Value(SExp::atom_from_string( + loc.clone(), + &helper_name, + ))); } + + // Reference callable + let mut call_args: Vec> = arg_sites + .iter() + .map(|_| { + let choice_of_expr: u16 = self.get_choice(); + self.choose_with_default(&body_forms, choice_of_expr, body_nil.clone()) + }) + .collect(); + call_args.insert( + 0, + Rc::new(BodyForm::Value(SExp::atom_from_string( + loc.clone(), + &helper_name, + ))), + ); + Rc::new(BodyForm::Call(loc.clone(), call_args)) } } @@ -602,26 +590,28 @@ impl Distribution for Standard { let input_val = input >> 4; // A new message type advances out of the prev phase. - match input_type { - 0 => { - let new_helper_kind = input_val & 3; - if new_helper_kind > MAX_HELPER_KIND_CPS { - cps.selectors.push(input_val); - continue; - } - - if new_helper_kind == 0 { - have_body = true; - cps.main = input_val; - continue; - } - - cps.helper_structures.push(input_val); + if input_type == 0 { + let new_helper_kind = input_val & 3; + if new_helper_kind > MAX_HELPER_KIND_CPS { + cps.selectors.push(input_val); + continue; } - 1..7 => cps.body_forms.push(input_val), - 8..10 => cps.arguments.push(input_val), - 11 => cps.constants.push(input_val), - _ => cps.selectors.push(input_val), + + if new_helper_kind == 0 { + have_body = true; + cps.main = input_val; + continue; + } + + cps.helper_structures.push(input_val); + } else if input_type < 8 { + cps.body_forms.push(input_val); + } else if input_type < 11 { + cps.arguments.push(input_val); + } else if input_type < 12 { + cps.constants.push(input_val); + } else { + cps.selectors.push(input_val); } } } diff --git a/src/lib.rs b/src/lib.rs index c022619dc..762f3ee7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(exclusive_range_pattern)] - #[macro_use] extern crate lazy_static; From 833be2c789aa0f1f2192150f91224e65a97268cc Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Jan 2023 10:13:39 -0800 Subject: [PATCH 13/21] fmt --- src/compiler/fuzzer.rs | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index 87a134aa2..2cb27f8e2 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -296,12 +296,9 @@ impl CollectProgramStructure { let choice_of_cond = b >> 3; let choice_of_then: u16 = self.get_choice(); let choice_of_else: u16 = self.get_choice(); - let use_cond = - self.choose_with_default(&body_forms, choice_of_cond, body_nil.clone()); - let use_then = - self.choose_with_default(&body_forms, choice_of_then, body_nil.clone()); - let use_else = - self.choose_with_default(&body_forms, choice_of_else, body_nil.clone()); + let use_cond = self.choose_with_default(&body_forms, choice_of_cond, body_nil.clone()); + let use_then = self.choose_with_default(&body_forms, choice_of_then, body_nil.clone()); + let use_else = self.choose_with_default(&body_forms, choice_of_else, body_nil.clone()); Rc::new(BodyForm::Call( loc.clone(), vec![ @@ -330,13 +327,13 @@ impl CollectProgramStructure { let use_a = self.choose_with_default(&body_forms, choice_of_a, body_nil.clone()); let use_b = self.choose_with_default(&body_forms, choice_of_b, body_nil.clone()); Rc::new(BodyForm::Call( - loc.clone(), - vec![ - Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![17]))), - use_a, - use_b, - ], - )) + loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(loc.clone(), vec![17]))), + use_a, + use_b, + ], + )) } else if selector == 10 { let choice_of_a = b >> 3; let choice_of_b: u16 = self.get_choice(); @@ -369,8 +366,7 @@ impl CollectProgramStructure { break; } - let body = - self.choose_with_default(&body_forms, choice_of_body, body_nil.clone()); + let body = self.choose_with_default(&body_forms, choice_of_body, body_nil.clone()); collected_names.push(arg_atom.clone()); collected_bindings.push(Rc::new(Binding { @@ -399,8 +395,8 @@ impl CollectProgramStructure { } let choice_of_helper = (b >> 3) as usize % self.helper_structures.len(); - let helper_spec = self.helper_structures - [choice_of_helper as usize % self.helper_structures.len()]; + let helper_spec = + self.helper_structures[choice_of_helper as usize % self.helper_structures.len()]; let choice_of_arg = helper_spec >> 3; let call_args = self.choose_with_default(&arguments, choice_of_arg, nil.clone()); let mut arg_sites = Vec::new(); From 4bafb0cd451813e48142f7af6c63110607157b21 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Jan 2023 12:10:27 -0800 Subject: [PATCH 14/21] clippy --- src/fuzzing/fuzzrng.rs | 7 ++++--- test/proggen/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/fuzzing/fuzzrng.rs b/src/fuzzing/fuzzrng.rs index 0e1ea9390..d7e3870d4 100644 --- a/src/fuzzing/fuzzrng.rs +++ b/src/fuzzing/fuzzrng.rs @@ -9,10 +9,10 @@ pub struct FuzzPseudoRng<'slice> { impl<'slice> FuzzPseudoRng<'slice> { pub fn new(slice: &'slice [u8]) -> Self { - return FuzzPseudoRng { - slice: slice, + FuzzPseudoRng { + slice, progress: 0, - }; + } } fn next_u8_untreated(&mut self) -> u8 { @@ -51,6 +51,7 @@ impl<'slice> RngCore for FuzzPseudoRng<'slice> { } #[inline(always)] + #[allow(clippy::needless_range_loop)] fn fill_bytes(&mut self, dest: &mut [u8]) { for i in 0..dest.len() { dest[i] = self.next_u8_untreated() diff --git a/test/proggen/Cargo.toml b/test/proggen/Cargo.toml index d4aeb5e64..70a8c03a2 100644 --- a/test/proggen/Cargo.toml +++ b/test/proggen/Cargo.toml @@ -14,4 +14,4 @@ rand = "0.8.5" [dependencies.clvm_tools_rs] path = "../.." -features = ["fuzzer"] \ No newline at end of file +features = ["fuzzer"] From c3e46961a3fb3b2b5df13d0da47b948db7656adc Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Jan 2023 12:32:44 -0800 Subject: [PATCH 15/21] fmt --- src/fuzzing/fuzzrng.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/fuzzing/fuzzrng.rs b/src/fuzzing/fuzzrng.rs index d7e3870d4..5bc4db312 100644 --- a/src/fuzzing/fuzzrng.rs +++ b/src/fuzzing/fuzzrng.rs @@ -9,10 +9,7 @@ pub struct FuzzPseudoRng<'slice> { impl<'slice> FuzzPseudoRng<'slice> { pub fn new(slice: &'slice [u8]) -> Self { - FuzzPseudoRng { - slice, - progress: 0, - } + FuzzPseudoRng { slice, progress: 0 } } fn next_u8_untreated(&mut self) -> u8 { From 4b1f2fca14f89f6f9af6913b893435d26b388d07 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Jan 2023 12:53:58 -0800 Subject: [PATCH 16/21] Some naming/comments --- test/proggen/src/main.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/proggen/src/main.rs b/test/proggen/src/main.rs index 752c12343..da7224f65 100644 --- a/test/proggen/src/main.rs +++ b/test/proggen/src/main.rs @@ -16,7 +16,11 @@ use clvm_tools_rs::compiler::srcloc::Srcloc; use clvm_tools_rs::fuzzing::fuzzrng::FuzzPseudoRng; use clvm_tools_rs::fuzzing::make_random_u64_seed; -fn do_program(dialect: Rc, buf: &[u8]) -> Rc { +// Create CollectProgramStructure and use it to generate a program. +// Return the program in SExp form. +// The result of CollectProgramStructure is a CompileForm so there are +// other things you can do with them as well. +fn build_program(dialect: Rc, buf: &[u8]) -> Rc { let mut fpr = FuzzPseudoRng::new(buf); let mut cps: CollectProgramStructure = fpr.gen(); let program = cps.to_program(); @@ -69,7 +73,7 @@ fn main() { let loc = Srcloc::start("*rng*"); let dialect = Rc::new(SExp::atom_from_string(loc, "*standard-cl-21*")); - let sexp = do_program(dialect.clone(), &buf); + let sexp = build_program(dialect.clone(), &buf); write_prog_to_db(&mut conn, &buf, sexp); for _ in 0..10000 { @@ -89,6 +93,7 @@ fn main() { } } + // Add entropy. let next_byte = rng.gen_range(0..=buf.len()); if next_byte >= buf.len() - 3 { for _ in 0..4 { @@ -99,7 +104,7 @@ fn main() { buf[next_byte + i] ^= rng.gen::(); } } - let sexp = do_program(dialect.clone(), &buf); + let sexp = build_program(dialect.clone(), &buf); eprintln!("{}", sexp); write_prog_to_db(&mut conn, &buf, sexp); } From d21006ab2667f0e432bcd3187a7a95455845790c Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Feb 2023 09:54:17 -0800 Subject: [PATCH 17/21] Add some test outputs for the fuzzer (these will change subsequently as new forms are introduced) --- src/tests/compiler/fuzzer.rs | 49 ++++++++++++++++++++++++++++++++++++ src/tests/compiler/mod.rs | 1 + 2 files changed, 50 insertions(+) create mode 100644 src/tests/compiler/fuzzer.rs diff --git a/src/tests/compiler/fuzzer.rs b/src/tests/compiler/fuzzer.rs new file mode 100644 index 000000000..d48d44998 --- /dev/null +++ b/src/tests/compiler/fuzzer.rs @@ -0,0 +1,49 @@ +use rand::prelude::*; +use crate::compiler::comptypes::CompileForm; +use crate::compiler::fuzzer::CollectProgramStructure; +use crate::fuzzing::fuzzrng::FuzzPseudoRng; + +fn produce_fuzz_program(b: &[u8]) -> CompileForm { + let mut rng = FuzzPseudoRng::new(b); + let mut cps: CollectProgramStructure = rng.gen(); + cps.to_program() +} + +#[test] +fn test_simple_fuzzer_output_1() { + let input: &[u8] = &[ + 0x00, 0x00, 0x00, 0xaf, 0xe8, 0x20, 0xb7, 0x82, + 0x07, 0x29, 0xae, 0x0f, 0x22, 0xb3, 0xf5, 0x5b + ]; + let cf = produce_fuzz_program(input); + assert_eq!( + cf.to_sexp().to_string(), + "(E (defmacro helper_0 C (18 (q) (q))) (q))" + ); +} + +#[test] +fn test_simple_fuzzer_output_2() { + let input: &[u8] = &[ + 0x00, 0x00, 0x00, 0xaf, 0xe8, 0x20, 0xb7, 0x82, + 0x07, 0x3f, 0x79, 0xaa, 0x72, 0xb3, 0xf5, 0x5b + ]; + let cf = produce_fuzz_program(input); + assert_eq!( + cf.to_sexp().to_string(), + "(E (defmacro helper_0 C (let ((A (18 (q) (q)))) (18 (q) (q)))) (q))" + ); +} + +#[test] +fn test_simple_fuzzer_output_3() { + let input: &[u8] = &[ + 0x00, 0x00, 0x00, 0x8c, 0x66, 0x36, 0xfd, 0xb3, + 0x5a, 0x80, 0x9d, 0x45, 0x9c, 0x0e, 0x91, 0x79 + ]; + let cf = produce_fuzz_program(input); + assert_eq!( + cf.to_sexp().to_string(), + "(A (18 (let ((B A) (D A)) A) A))" + ); +} diff --git a/src/tests/compiler/mod.rs b/src/tests/compiler/mod.rs index 09b9beff2..a15d87464 100644 --- a/src/tests/compiler/mod.rs +++ b/src/tests/compiler/mod.rs @@ -7,6 +7,7 @@ use crate::compiler::srcloc::{Srcloc, Until}; mod clvm; mod compiler; mod evaluate; +mod fuzzer; mod repl; mod srcloc; mod usecheck; From b4917970a97fe0da164e2bc9b2e0f40125bbe8d1 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Feb 2023 10:00:20 -0800 Subject: [PATCH 18/21] fmt + clippy --- src/tests/compiler/fuzzer.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/tests/compiler/fuzzer.rs b/src/tests/compiler/fuzzer.rs index d48d44998..7184a679d 100644 --- a/src/tests/compiler/fuzzer.rs +++ b/src/tests/compiler/fuzzer.rs @@ -1,7 +1,7 @@ -use rand::prelude::*; use crate::compiler::comptypes::CompileForm; use crate::compiler::fuzzer::CollectProgramStructure; use crate::fuzzing::fuzzrng::FuzzPseudoRng; +use rand::prelude::*; fn produce_fuzz_program(b: &[u8]) -> CompileForm { let mut rng = FuzzPseudoRng::new(b); @@ -12,8 +12,8 @@ fn produce_fuzz_program(b: &[u8]) -> CompileForm { #[test] fn test_simple_fuzzer_output_1() { let input: &[u8] = &[ - 0x00, 0x00, 0x00, 0xaf, 0xe8, 0x20, 0xb7, 0x82, - 0x07, 0x29, 0xae, 0x0f, 0x22, 0xb3, 0xf5, 0x5b + 0x00, 0x00, 0x00, 0xaf, 0xe8, 0x20, 0xb7, 0x82, 0x07, 0x29, 0xae, 0x0f, 0x22, 0xb3, 0xf5, + 0x5b, ]; let cf = produce_fuzz_program(input); assert_eq!( @@ -25,8 +25,8 @@ fn test_simple_fuzzer_output_1() { #[test] fn test_simple_fuzzer_output_2() { let input: &[u8] = &[ - 0x00, 0x00, 0x00, 0xaf, 0xe8, 0x20, 0xb7, 0x82, - 0x07, 0x3f, 0x79, 0xaa, 0x72, 0xb3, 0xf5, 0x5b + 0x00, 0x00, 0x00, 0xaf, 0xe8, 0x20, 0xb7, 0x82, 0x07, 0x3f, 0x79, 0xaa, 0x72, 0xb3, 0xf5, + 0x5b, ]; let cf = produce_fuzz_program(input); assert_eq!( @@ -38,12 +38,9 @@ fn test_simple_fuzzer_output_2() { #[test] fn test_simple_fuzzer_output_3() { let input: &[u8] = &[ - 0x00, 0x00, 0x00, 0x8c, 0x66, 0x36, 0xfd, 0xb3, - 0x5a, 0x80, 0x9d, 0x45, 0x9c, 0x0e, 0x91, 0x79 + 0x00, 0x00, 0x00, 0x8c, 0x66, 0x36, 0xfd, 0xb3, 0x5a, 0x80, 0x9d, 0x45, 0x9c, 0x0e, 0x91, + 0x79, ]; let cf = produce_fuzz_program(input); - assert_eq!( - cf.to_sexp().to_string(), - "(A (18 (let ((B A) (D A)) A) A))" - ); + assert_eq!(cf.to_sexp().to_string(), "(A (18 (let ((B A) (D A)) A) A))"); } From 8c02e1b0c16eb2d5ece85f129f48831b3ab3901b Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Feb 2023 12:03:13 -0800 Subject: [PATCH 19/21] merge up + fmt + clippy --- src/compiler/frontend.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index c6d28878e..0c34816ec 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -113,7 +113,6 @@ fn calculate_live_helpers( .collect(); needed_helpers = needed_helpers .union(&even_newer_names) - .into_iter() .map(|x| x.to_vec()) .collect(); } From a9887876bf14447d9f5790437d4069850be328e7 Mon Sep 17 00:00:00 2001 From: arty Date: Sat, 4 Feb 2023 11:47:54 -0800 Subject: [PATCH 20/21] Merge up --- src/compiler/fuzzer.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index 2cb27f8e2..3853c82c1 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -8,8 +8,8 @@ use std::rc::Rc; use crate::classic::clvm::__type_compatibility__::bi_one; use crate::compiler::comptypes::{ - Binding, BodyForm, CompileForm, DefconstData, DefmacData, DefunData, HelperForm, LetData, - LetFormKind, + Binding, BodyForm, CompileForm, ConstantKind, DefconstData, DefmacData, DefunData, HelperForm, + LetData, LetFormKind, }; use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; @@ -455,6 +455,7 @@ impl CollectProgramStructure { 0 => HelperForm::Defconstant(DefconstData { loc: loc.clone(), name: helper_name, + kind: ConstantKind::Simple, kw: None, nl: loc.clone(), body: body, From ba6a2020e962cf929ff9266503b8b238c0ad07a6 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 13 Sep 2023 14:34:45 -0700 Subject: [PATCH 21/21] Merge up --- src/compiler/fuzzer.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/compiler/fuzzer.rs b/src/compiler/fuzzer.rs index c2e75ea65..9c123c2f1 100644 --- a/src/compiler/fuzzer.rs +++ b/src/compiler/fuzzer.rs @@ -157,9 +157,9 @@ fn rewrite_identifiers_bodyform(in_scope: &Vec>, body_form: &BodyForm) - } }) .collect(); - let new_tail = tail.as_ref().map(|t| { - Rc::new(rewrite_identifiers_bodyform(in_scope, t.borrow())) - }); + let new_tail = tail + .as_ref() + .map(|t| Rc::new(rewrite_identifiers_bodyform(in_scope, t.borrow()))); BodyForm::Call(l.clone(), new_args, new_tail) } _ => body_form.clone(), @@ -310,7 +310,7 @@ impl CollectProgramStructure { use_then, use_else, ], - None + None, )) } else if selector == 8 { let choice_of_a = b >> 3; @@ -324,7 +324,7 @@ impl CollectProgramStructure { use_a, use_b, ], - None + None, )) } else if selector == 9 { let choice_of_a = b >> 3; @@ -338,7 +338,7 @@ impl CollectProgramStructure { use_a, use_b, ], - None + None, )) } else if selector == 10 { let choice_of_a = b >> 3; @@ -352,7 +352,7 @@ impl CollectProgramStructure { use_a, use_b, ], - None + None, )) } else if selector == 11 { // Synthesize a let form.