From 87db1bfdb6fc3507814efb3e10d1457c8603923a Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Tue, 3 Aug 2021 13:28:57 -0700 Subject: [PATCH 01/17] [RFC] Add an RFC for bit and byte conversions. --- docs/rfc/009-bit-byte-conversions.md | 265 +++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 docs/rfc/009-bit-byte-conversions.md diff --git a/docs/rfc/009-bit-byte-conversions.md b/docs/rfc/009-bit-byte-conversions.md new file mode 100644 index 0000000000..513b408b94 --- /dev/null +++ b/docs/rfc/009-bit-byte-conversions.md @@ -0,0 +1,265 @@ +# Leo RFC 009: Conversions with Bits and Bytes + +## Authors + +- Max Bruce +- Collin Chin +- Alessandro Coglio +- Eric McCarthy +- Jon Pavlik +- Damir Shamanaev +- Damon Sicore +- Howard Wu + +## Status + +DRAFT + +# Summary + +This RFC proposes the addition of natively implemented global functions to perform conversions +between Leo integer values and sequences of bits or bytes in big endian or little endian order. +This RFC also proposes a future transition from these functions to methods associated to the integer types. + +# Motivation + +Conversions of integers to bits and bytes are fairly common in programming languages. +Use case include communication with the external world +(since external data is sometimes represented as bits and bytes rather than higher-level data structures), +and serialization/deserialization for cryptographic purposes (e.g. hashing data). + +# Design + +## Concepts + +The Leo integer values can be thought of sequences of bits. +Therefore, it makes sense to convert between integer values and their corresponding sequences of bits; +the sequences of bits can be in little or big endian order (i.e. least vs. most significant bit first), +naturally leading to two possible conversions. +Obviously, the bits represent the integers in base 2. + +Since all the Leo integer values consist of multiples of 8 bits, +it also makes sense to convert between integer values and squences of bytes, +which represents the integers in base 256. +Again, the bytes may be in little or big endian order. + +It could also make sense to convert between integers consisting of `N` bits +and sequences of "words" of `M` bits if `N` is a multiple of `M`, +e.g. convert a `u32` into a sequence of two `u16`s, or convert a `u128` into a sequence of four `u32`s. +However, the case in which `M` is 1 (bits) or 8 (bytes) is by far the most common, +and therefore the initial focus of this RFC; +nonetheless, it seems valuable to keep these possible generalizations in mind as we work though this initial design. + +Another possible generalization is to lift these conversions to sequences, +e.g. converting from a sequence of integer values to a sequence of bits or bytes +by concatenating the results of converting the integer values, +and converting from a sequence of bits or bytes to a sequence of integer values +by grouping the bits or bytes into chunks and converting each chunk into an integer. +For instance, a sequence of 4 `u32` values can be turned into a sequence of 32 bytes or a sequence of 128 bits. +Note that, in these cases, the endianness only applies to the individual element conversion, +not to the ordering of the integer values, which should be preserved by the conversion. + +Besides integers, it could make sense to consider converting other Leo values between bits and bytes, +namely characters, field elements, group elements, and addresses (but perhaps not booleans). +If this is further extended to aggregate values (tuples, arrays, and circuits), +then this moves towards a general serialization/deserialization library for Leo, which could be a separate feature. + +## Representation of Bits + +In Leo's current type system, bits can be represented as `bool` values. +These are not quite the numbers 0 and 1, but they are isomorphic, and it is easy to convert between booleans and bits: +```ts +// convert a boolean x to a bit: +(x ? 1 : 0) + +// convert f bit y to a boolean: +(y == 1) +``` + +If Leo had a type `u1` for unsigned 1-bit integers, we could use that instead of `bool`. +Separately from this RFC, such a type could be added. +There is also an outstanding proposal (not in an RFC currently) to support types `uN` and `iN` for every positive `N`, +in which case `u1` would be an instance of that. + +## Representation of Bytes + +The type `u8` is the natural way to represent a byte. +The type `i8` is isomorphic to that, but we tend to think of bytes as unsigned. + +## Representation of Sequences + +This applies to the sequence of bits or bytes that a Leo integer converts to or from. +E.g. a `u32` is converted to/from a sequence of bits or bytes. + +Sequences in Leo may be ntaurally represented as arrays or tuples. +Arrays are more flexible; in particular, they allow indexing via expressions rather than just numbers, unlike tuples. +Thus, arrays are the natural choice to represent these sequences. + +## Conversion Functions + +We propose the following global functions, +for which we write declarations without bodies below, +since the implementation is native. +(It is a separate issue whether the syntax below should be allowed, +in order to represent natively implemented functions, +or whether there should be a more explicit indication such as `native` in Java). + +These are tentative names, which we can tweak. +What is more important is the selection of operations, and their input/output types. + +### Conversions between Integers and Bits + +```ts +// unsigned to bits, little and big endian +function u8_to_bits_le(x: u8) -> [bool; 8]; +function u8_to_bits_be(x: u8) -> [bool; 8]; +function u16_to_bits_le(x: u16) -> [bool; 16]; +function u16_to_bits_be(x: u16) -> [bool; 16]; +function u32_to_bits_le(x: u32) -> [bool; 32]; +function u32_to_bits_be(x: u32) -> [bool; 32]; +function u64_to_bits_le(x: u64) -> [bool; 64]; +function u64_to_bits_be(x: u64) -> [bool; 64]; +function u128_to_bits_le(x: u128) -> [bool; 128]; +function u128_to_bits_be(x: u128) -> [bool; 128]; + +// signed to bits, little and big endian +function i8_to_bits_le(x: i8) -> [bool; 8]; +function i8_to_bits_be(x: i8) -> [bool; 8]; +function i16_to_bits_le(x: i16) -> [bool; 16]; +function i16_to_bits_be(x: i16) -> [bool; 16]; +function i32_to_bits_le(x: i32) -> [bool; 32]; +function i32_to_bits_be(x: i32) -> [bool; 32]; +function i64_to_bits_le(x: i64) -> [bool; 64]; +function i64_to_bits_be(x: i64) -> [bool; 64]; +function i128_to_bits_le(x: i128) -> [bool; 128]; +function i128_to_bits_be(x: i128) -> [bool; 128]; + +// unsigned from bits, little and big endian +function u8_from_bits_le(x: [bool; 8]) -> u8; +function u8_from_bits_be(x: [bool; 8]) -> u8; +function u16_from_bits_le(x: [bool; 16]) -> u16; +function u16_from_bits_be(x: [bool; 16]) -> u16; +function u32_from_bits_le(x: [bool; 32]) -> u32; +function u32_from_bits_be(x: [bool; 32]) -> u32; +function u64_from_bits_le(x: [bool; 64]) -> u64; +function u64_from_bits_be(x: [bool; 64]) -> u64; +function u128_from_bits_le(x: [bool; 128]) -> u128; +function u128_from_bits_be(x: [bool; 128]) -> u128; + +// signed from bits, little and big endian +function i8_from_bits_le(x: [bool; 8]) -> i8; +function i8_from_bits_be(x: [bool; 8]) -> i8; +function i16_from_bits_le(x: [bool; 16]) -> i16; +function i16_from_bits_be(x: [bool; 16]) -> i16; +function i32_from_bits_le(x: [bool; 32]) -> i32; +function i32_from_bits_be(x: [bool; 32]) -> i32; +function i64_from_bits_le(x: [bool; 64]) -> i64; +function i64_from_bits_be(x: [bool; 64]) -> i64; +function i128_from_bits_le(x: [bool; 128]) -> i128; +function i128_from_bits_be(x: [bool; 128]) -> i128; +``` + +### Conversions between Integers and Bytes + +```ts +// unsigned to bytes, little and big endian +function u16_to_bytes_le(x: u16) -> [u8; 2]; +function u16_to_bytes_be(x: u16) -> [u8; 2]; +function u32_to_bytes_le(x: u32) -> [u8; 4]; +function u32_to_bytes_be(x: u32) -> [u8; 4]; +function u64_to_bytes_le(x: u64) -> [u8; 8]; +function u64_to_bytes_be(x: u64) -> [u8; 8]; +function u128_to_bytes_le(x: u128) -> [u8; 16]; +function u128_to_bytes_be(x: u128) -> [u8; 16]; + +// signed to bytes, little and big endian +function i16_to_bytes_le(x: i16) -> [u8; 2]; +function i16_to_bytes_be(x: i16) -> [u8; 2]; +function i32_to_bytes_le(x: i32) -> [u8; 4]; +function i32_to_bytes_be(x: i32) -> [u8; 4]; +function i64_to_bytes_le(x: i64) -> [u8; 8]; +function i64_to_bytes_be(x: i64) -> [u8; 8]; +function i128_to_bytes_le(x: i128) -> [u8; 16]; +function i128_to_bytes_be(x: i128) -> [u8; 16]; + +// unsigned from bytes, little and big endian +function u16_from_bytes_le(x: [u8; 2]) -> u16; +function u16_from_bytes_be(x: [u8; 2]) -> u16; +function u32_from_bytes_le(x: [u8; 4]) -> u32; +function u32_from_bytes_be(x: [u8; 4]) -> u32; +function u64_from_bytes_le(x: [u8; 8]) -> u64; +function u64_from_bytes_be(x: [u8; 8]) -> u64; +function u128_from_bytes_le(x: [u8; 16]) -> u128; +function u128_from_bytes_be(x: [u8; 16]) -> u128; + +// signed from bytes, little and big endian +function i16_from_bytes_le(x: [u8; 2]) -> i16; +function i16_from_bytes_be(x: [u8; 2]) -> i16; +function i32_from_bytes_le(x: [u8; 4]) -> i32; +function i32_from_bytes_be(x: [u8; 4]) -> i32; +function i64_from_bytes_le(x: [u8; 8]) -> i64; +function i64_from_bytes_be(x: [u8; 8]) -> i64; +function i128_from_bytes_le(x: [u8; 16]) -> i128; +function i128_from_bytes_be(x: [u8; 16]) -> i128; +``` + +## Transition to Methods + +Once a separate proposal for adding methods to Leo scalar types is realized, +we may want to turn the global functions listed above into methods, +deprecating the global functions, and eventually eliminating them. + +Conversions to bits or bytes will be instance methods of the integer types, +e.g. `u8` will include an instance method `to_bits_le` that takes no arguments and that returns a `[bool; 8]`. +Example: +```ts +let int: u8 = 12; +let bits: [bool; 8] = int.to_bits_le(); +console.assert(bits == [false, false, true, true, false, false, false, false]); // 00110000 (little endian) +``` + +Conversions from bits or bytes will be static methods of the integer types, +e.g. `u8` will include a static metod `from_bits_le` that takes a `[bool; 8]` argument and returns a `u8`. +Example: +```ts +let bits: [bool; 8] = [false, false, true, true, false, false, false, false]; // 00110000 (little endian) +let int = u8::from_bits_le(bits); +console.assert(int == 12); +``` + +# Drawbacks + +This does not seem to bring any drawbacks. + +# Effect on Ecosystem + +None. + +# Alternatives + +## Pure Leo Implementation + +These conversions can be realized in Leo (i.e. without native implementations), +provided that Leo is extended with certain operations that are already separately planned: +* Integer division and remainder, along with type casts, could be used. +* Bitwise shifts and masks, along with type casts, could be used. + +However, compiling the Leo code that realizes the conversions may result in less efficient R1CS than the native ones. + +## Naming Bit and Byte Types Explicitly + +Names like `u8_to_bits_le` and `u32_to_bytes_le` talk about bits and bytes, +therefore relying on a choice of representation for bits and bytes, +which is `bool` for bits and `u8` for bytes as explained above. +An alternative is to have names like `u8_to_bools_le` and `u32_to_u8s_le`, +which explicate the representation of bits and bytes in the name, +and open the door to additional conversions to different representations. +In particular, if and when Leo is extended with a type `u1` for bits, +there could be additional operations like `u8_to_u1s_le`. + +This more explicit naming scheme also provides a path towards extending +bit and byte conversions to more generic "word" conversions, +such as `u64_to_u16s_le`, which would turn a `u64` into a `[u16; 4]`. +In general, it makes sense to convert between `uN` or `iN` and `[uM; P]` when `N == M * P`. +If Leo were extended with types `uN` and `iN` for all positive `N` as proposed elsewhere, +there could be a family of all such conversions. From fe3de3900e6ba5d0ae9886bcd24ff2ff7e25835f Mon Sep 17 00:00:00 2001 From: gluaxspeed Date: Thu, 12 Aug 2021 01:30:24 -0700 Subject: [PATCH 02/17] add rfc for primtive types as circuits --- docs/rfc/009-primitive-type-circuits.md | 64 +++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 docs/rfc/009-primitive-type-circuits.md diff --git a/docs/rfc/009-primitive-type-circuits.md b/docs/rfc/009-primitive-type-circuits.md new file mode 100644 index 0000000000..7d2e461b2d --- /dev/null +++ b/docs/rfc/009-primitive-type-circuits.md @@ -0,0 +1,64 @@ +# Leo RFC 001: Initial String Support + +## Authors + +- Max Bruce +- Collin Chin +- Alessandro Coglio +- Eric McCarthy +- Jon Pavlik +- Damir Shamanaev +- Damon Sicore +- Howard Wu + +## Status + +DRAFT + +## Summary + +This RFC proposes that the primitive types in Leo (integers, fields, etc.) are treated as circuits. The actual type primitives would still exist within the compiler and language. However, whenever a type primitive is encountered, it would be treated as a circuit(similar to Java types being objects). Note that this would not affect circuit synthesis. + +## Motivation + +Several languages have their types represented by an object within the language itself. This approach allows for a clean interface to provide built-in methods or static members for these basic types. + +## Design + +### Semantics + +Leo already has support for circuits. As such, the change would occur mainly during the parsing stage. However, we would still validate the parsing of literals/tuple-expressions/array-expressions the same way; the resulting type would just be a circuit. When we encounter either implicit types or an explicitly typed system, they would be parsed as a circuit. + +We could implement the circuits internally as follows: + +```ts +circuit U8 { + data: u8 +} +``` + +As for AST clarity's sake, these circuits should still be written to the AST the same way as the current primitives are. + +It would benefit us to store these circuits in a separate list of circuits on the AST that are pre-defined. + +All current operations on these circuits representing the basic functions should still work. These operations can easily be implemented by just leveraging the actual type primitive stored within the circuit. + +Now methods and static members would be first-class citizens of the circuits treated similarly to current operations like existing primitive operators. For example, in the following: + +```ts +let x = 1u8.to_bits(); +``` + +the method call would be treated as a gadget call. This implementation would save us implementing Leo methods the same way as blake2s currently is. + +## Drawbacks + +This change adds more complexity to the language. + +## Effect on Ecosystem + +None. All currently valid Leo programs would still be valid after this proposal. + +## Alternatives + +For implementing built-in operators, we could also allow operator overloading and then have a default overloaded method on these circuits. From f1384787eedb8b92736987f22c658f990614c2c5 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Fri, 13 Aug 2021 12:00:19 -0700 Subject: [PATCH 03/17] [RFC] Initial proposal for native functions. --- docs/rfc/010-native-functions.md | 195 +++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 docs/rfc/010-native-functions.md diff --git a/docs/rfc/010-native-functions.md b/docs/rfc/010-native-functions.md new file mode 100644 index 0000000000..3760e5478b --- /dev/null +++ b/docs/rfc/010-native-functions.md @@ -0,0 +1,195 @@ +# Leo RFC 010: Native Functions + +## Authors + +- Max Bruce +- Collin Chin +- Alessandro Coglio +- Eric McCarthy +- Jon Pavlik +- Damir Shamanaev +- Damon Sicore +- Howard Wu + +## Status + +DRAFT + +# Summary + +This RFC proposes an approach to handling natively implemented functions ('native functions', for short) in Leo, +that is functions implemented not via Leo code but (in essence) via Rust code. +Currently there is just one such function, namely BLAKE2s. +The scope of this proposal is limited to native functions defined by the developers of Leo itself, +not by users of Leo (i.e. developers of applications written in Leo). + +The approach proposed here is to allow (global and member) Leo functions to have no defining bodies, +in which case they are regarded as natively implemented; +this is only allowed in Leo files that contain standard/core libraries, provided with the Leo toolchain. +Most of the compiler can work essentially in the same way as it does now; +at R1CS generation time, native functions must be recognized, and turned into the known gadgets that implement them. + +# Motivation + +Many languages support native functions (here we generically use 'functions' to also denote methods), +where 'native' refers to the fact that the functions are implemented not in the language under consideration, +but rather in the language used to implement the language under consideration. +For instance, Java supports native methods that are implemented in C rather than Java. + +There are two main reasons for native functions in programming languages: +1. The functionality cannot be expressed at all in the language under consideration, + e.g. Java has no constructs to print on screen, making a native implementation necessary. +2. The functionality can be realized more efficiently in the native language. + +The first reason above may not apply to Leo, at least currently, +as Leo's intended use is mainly for "pure computations" rather than interactions with the external world. +However, we note that console statements could be regarded as native functions (as opposed to "ad hoc" statements), +and this may be in fact the path to pursue if we extend the scope of console features (e.g. even to full GUIs), +as has been recently proposed (we emphasize that the console code is not meant to be compiled to R1CS). + +The second reason above applies to Leo right now. +While there is currently just one native function supported in Leo, namely BLAKE2s, +it is conceivable that there may be other cryptographic (or non-cryptographic) functions +for which hand-crafted R1CS gadgets are available +that are more efficient than what the Leo compiler would generate if their functionality were written in Leo. +While we will continue working towards making the Leo compiler better, +and perhaps eventually capable to generate R1CS whose efficiency is competitive with hand-crafted gadgets, +this will take time, and in the meanwhile new and more native functions may be added, +resulting in a sort of arms race. +In other words, it is conceivable that Leo will need to support native functions in the foreseeable future. + +Languages typically come with standard/core libraries that application developers can readily use. +Even though the Leo standard/core libraries are currently limited (perhaps just to BLAKE2s), +it seems likely that we will want to provide more extensive standard/core libraries, +not just for cryptographic functions, but also for data structures and operations on them. + +The just mentioned use case of data structures brings about an important point. +Leo circuit types are reasonable ways to provide library data structures, +as they support static and instance member functions that realize operations on those data structures. +Just like some Java library classes provide a mix of native and non-native methods, +we could imagine certain Leo library circuit types providing a mix of native and non-native member functions, e.g.: +```ts +circuit Point2D { + x: u32; + y: u32; + function origin() -> Point2D { ... } // probably non-native + function move(mut self, delta_x: u32, delta_y: u32) { ... } // probably non-native + function distance(self, other:Point2D); // maybe native (involves square root) +} +``` + +Our initial motivation for naive functions is limited to Leo standard/core libraries, +not to user-defined libraries or applications. +That is, only the developers of the Leo language will be able to create native functions. +Leo users, i.e. developers of Leo applications, will be able to use the provided native functions, +but not to create their own. +If support for user-defined native functions may become desired in the future, it will be discussed in a separate RFC. + +# Design + +## Background + +### Current Approach to Native Functions + +The BLAKE2s native function is currently implemented as follows (as a high-level view): +1. Prior to type checking/inference, its declaration (without a defining body) + is programmatically added to the program under consideration. + This way, the input and output types of the BLAKE2s function can be used to type-check code that calls it. +2. At R1CS generation time, when the BLAKE2s function is compiled, it is recognized as native and, + instead of translating its body to R1CS (which is not possible as the function has no Leo body), + a known BLAKE2s gadget is used. + +This approach is fine for a single native function, but may not be the best for a richer collection of native functions. +In particular, consider the `Point2D` example above, which has a mix of native and non-native functions: +presumably, we would like to write at least the non-native functions of `Point2D` directly in a Leo file, +as opposed to programmatically generating them prior to type checking/inference. + +### Multi-File Compilation + +Leo already supports the compilation of multiple files that form a program, via packages and importing. +This capability is independent from native functions. + +We note that, for the purpose of type checking code that calls a function `f`, +the defining body of `f` is irrelevant: only the input and output types of `f` are relevant. +The defining body is of course type-checked when `f` itself is type-checked, +and furthermore the defining body is obviously needed to generate R1CS, +but the point here is that only the input and output types of `f` are needed to type-check code that calls `f`. +In particular, this means that, if a Leo file imports a package, +only the type information from the package is needed to type-check the file that imports the package. +Conceptually, each package exports a symbol table, used (and sufficient) to type-check files that import that package. + +## Proposal + +we propose to: +1. Allow declarations of (global and member) functions to have no defining body, signaling that the function is native. +2. Extend the AST and ASG to allow functions to have no bodies. +3. Have the compiler allow empty function bodies only in standard/core library files, which should be known. +4. Have type checking/inference "skip over" absent function bodies. +5. At R1CS generation time, when a function without body is encountered, find and use the known gadget for it. + +Currently the ABNF grammar requires function declarations to have a defining body (a block), i.e. to be implemented in Leo: +``` +function-declaration = *annotation %s"function" identifier + "(" [ function-parameters ] ")" [ "->" type ] + block +``` +We propose to relax the rule as follows: +``` +function-declaration = *annotation %s"function" identifier + "(" [ function-parameters ] ")" [ "->" type ] + ( block / ";" ) +``` +This allows a function declaration to have a terminating semicolon instead of a block. + +Since we do not have anything like abstract methods in Leo, this is a workable way to indicate native functions. +However, it is easy, if desired, to have a more promiment indication, such as a `native` keyword, or an annotation. + +It may be necessary to extend the AST and ASG to accommodate function bodies to be optional, +although this may be already the case for representing BLAKE2s in its current form described above. + +The compiler should know which files are part of the Leo standard/core libraries and which ones are not. +Functions without bodies will be only allowed to appear in those files. +It will be an error if any other file (e.g. user-defined) contains functions without bodies. +Type checking/inference may be where we make this check, or perhaps in some other phase. + +Because of the already existing support for multi-file compilation described above, +no essential change is needed in the compiler's type checking/inference. +We just need to make sure that functions without bodies are expected and properly handled +(i.e. their input and output types must be checked and added to the proper symbol tables, +but their absent bodies must be skipped); +this may already be the case, for the treatment of BLAKE2s described above. + +The main change is in R1CS generation. +Normally, when a function definition is encountered, its Leo body is translated to R1CS. +For a native function, we need to find and use a known gadget instead. +The compiler must know a mapping from native functions in the standard/core libraries +to the R1CS gadgets that implement them, so it should be just a matter of selecting the appropriate one. +Some of this logic must be already present, in order to detect and select the BLAkE2s gadget. + +# Drawbacks + +This does not seem to bring any drawbacks. +A capability for native functions (for BLAKE2s) already exists; +this RFC proposes a way to make it more flexible, +with mild (and likely simplifying) changes to the compiler. + +# Effect on Ecosystem + +This should help support richer standard/core libraries for Leo. + +# Alternatives + +Instead of storing declarations of native functions in standard/core files as proposed above, +we could programmatically generate them as currently done for BLAKE2s. +Macros may be used to generate families of similar function declarations. + +However, consider `Point2D` above, which has a mix or native and non-native functions. +One approach is to programmatically generate the whole `Point2D` declarative, +with both native and non-native functions. +But it seems that a Leo file would be clearer and more maintainable than a Rust string in the compiler. +We could think of splitting the non-native and native functions of `Point2D`: +the former in a Leo file, and the latter programmatically added. +Again, this looks more complicated than just declaring native funcions in Leo files. + +In summary, accommodating native functions in Leo standard/core file +should be doable with mild and possibly simplifying changes to the current Leo compiler. From 54eb95c62de9c305539a307ca4265f5200bdd38e Mon Sep 17 00:00:00 2001 From: gluaxspeed Date: Fri, 13 Aug 2021 18:21:39 -0700 Subject: [PATCH 04/17] Change RFC based on discussion --- docs/rfc/009-primitive-type-circuits.md | 64 --------------- .../009-scalar-type-accesses-and-methods.md | 77 +++++++++++++++++++ 2 files changed, 77 insertions(+), 64 deletions(-) delete mode 100644 docs/rfc/009-primitive-type-circuits.md create mode 100644 docs/rfc/009-scalar-type-accesses-and-methods.md diff --git a/docs/rfc/009-primitive-type-circuits.md b/docs/rfc/009-primitive-type-circuits.md deleted file mode 100644 index 7d2e461b2d..0000000000 --- a/docs/rfc/009-primitive-type-circuits.md +++ /dev/null @@ -1,64 +0,0 @@ -# Leo RFC 001: Initial String Support - -## Authors - -- Max Bruce -- Collin Chin -- Alessandro Coglio -- Eric McCarthy -- Jon Pavlik -- Damir Shamanaev -- Damon Sicore -- Howard Wu - -## Status - -DRAFT - -## Summary - -This RFC proposes that the primitive types in Leo (integers, fields, etc.) are treated as circuits. The actual type primitives would still exist within the compiler and language. However, whenever a type primitive is encountered, it would be treated as a circuit(similar to Java types being objects). Note that this would not affect circuit synthesis. - -## Motivation - -Several languages have their types represented by an object within the language itself. This approach allows for a clean interface to provide built-in methods or static members for these basic types. - -## Design - -### Semantics - -Leo already has support for circuits. As such, the change would occur mainly during the parsing stage. However, we would still validate the parsing of literals/tuple-expressions/array-expressions the same way; the resulting type would just be a circuit. When we encounter either implicit types or an explicitly typed system, they would be parsed as a circuit. - -We could implement the circuits internally as follows: - -```ts -circuit U8 { - data: u8 -} -``` - -As for AST clarity's sake, these circuits should still be written to the AST the same way as the current primitives are. - -It would benefit us to store these circuits in a separate list of circuits on the AST that are pre-defined. - -All current operations on these circuits representing the basic functions should still work. These operations can easily be implemented by just leveraging the actual type primitive stored within the circuit. - -Now methods and static members would be first-class citizens of the circuits treated similarly to current operations like existing primitive operators. For example, in the following: - -```ts -let x = 1u8.to_bits(); -``` - -the method call would be treated as a gadget call. This implementation would save us implementing Leo methods the same way as blake2s currently is. - -## Drawbacks - -This change adds more complexity to the language. - -## Effect on Ecosystem - -None. All currently valid Leo programs would still be valid after this proposal. - -## Alternatives - -For implementing built-in operators, we could also allow operator overloading and then have a default overloaded method on these circuits. diff --git a/docs/rfc/009-scalar-type-accesses-and-methods.md b/docs/rfc/009-scalar-type-accesses-and-methods.md new file mode 100644 index 0000000000..d359dd715b --- /dev/null +++ b/docs/rfc/009-scalar-type-accesses-and-methods.md @@ -0,0 +1,77 @@ +# Leo RFC 009: Scalar Type Accesses And Methods + +## Authors + +- Max Bruce +- Collin Chin +- Alessandro Coglio +- Eric McCarthy +- Jon Pavlik +- Damir Shamanaev +- Damon Sicore +- Howard Wu + +## Status + +DRAFT + +## Summary + +This RFC proposes two things: + +1. The scalar types in Leo (integers, fields, etc.) can have static methods. +2. The scalar types in Leo (integers, fields, etc.) can have static constants. +3. Those values that have a scalar type can have methods directly on them. + +## Motivation + +This approach allows for a clean interface to provide built-in methods or static members for these basic types. + +## Design + +### Semantics + +Firstly we would have to modify both the ABNF and parsing of Leo to allow static method calls onto a scalar type. + +The ABNF would look as follows: + +```abnf +; This is an existing old rule +scalar-type = boolean-type / arithmetic-type / address-type / character-type + +; This is an existing old rule +circuit-type = identifier / self-type + +; Add this rule. +named-type = circuit-type / scalar-type ; new rule + +; Modify this rule: +postfix-expression = primary-expression + / postfix-expression "." natural + / postfix-expression "." identifier + / identifier function-arguments + / postfix-expression "." identifier function-arguments + / named-type "::" identifier function-arguments ; this used to be a circuit-type + / postfix-expression "[" expression "]" + / postfix-expression "[" [expression] ".." [expression] "]" +``` + +Now methods and static members would be first-class citizens of scalar types and their values. For example, in the following could be done: + +```ts +let x = 1u8.to_bits(); // A method call on on a scalar value itself +let x = u8::MAX; // A constant value on the scalar type +let y = u8::to_bits(1u8); // A static method on the scalar type +``` + +## Drawbacks + +This change adds more complexity to the language. + +## Effect on Ecosystem + +None. The new parsing changes would not break any older programs. + +## Alternatives + +None. From 1b34fa0538c720b346f3c93cdbe73c3da791d1b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Aug 2021 10:18:57 +0000 Subject: [PATCH 05/17] Bump snarkvm-curves from 0.7.8 to 0.7.9 Bumps [snarkvm-curves](https://github.com/AleoHQ/snarkVM) from 0.7.8 to 0.7.9. - [Release notes](https://github.com/AleoHQ/snarkVM/releases) - [Commits](https://github.com/AleoHQ/snarkVM/compare/v0.7.8...v0.7.9) --- updated-dependencies: - dependency-name: snarkvm-curves dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 16 ++++++++-------- Cargo.toml | 2 +- compiler/Cargo.toml | 2 +- state/Cargo.toml | 2 +- synthesizer/Cargo.toml | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f109d381e2..28aa497906 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2456,9 +2456,9 @@ dependencies = [ [[package]] name = "snarkvm-curves" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "010ae5c95693279db519e4a8525a8a3145edc8e36198efdfaf250622f4540cc1" +checksum = "83b4de7cd1533c67dd386058b631d7e5ea8b2063ebca212159b13fc1a94ff4a7" dependencies = [ "derivative", "rand 0.8.4", @@ -2472,9 +2472,9 @@ dependencies = [ [[package]] name = "snarkvm-derives" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e963ae4209f0166a619ab9266ce71c6f9228861ec55615a1b6154d673ffc158" +checksum = "3e854888634305d8c5c79fe59adaae593971a8b29d3148834f698141b16c2c7b" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -2517,9 +2517,9 @@ dependencies = [ [[package]] name = "snarkvm-fields" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "761cb4c19d6685ac9d1d3a6eb1619600334bcf80dc6ac742cc38f4fe349ba871" +checksum = "bca141a8eae489ea39600b04f0a642059ce076bd3a7d21704b38b90fc87c37f0" dependencies = [ "anyhow", "bincode", @@ -2630,9 +2630,9 @@ dependencies = [ [[package]] name = "snarkvm-utilities" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0842ff685e625cb7a2f9ddc7ca1b1560d2a3e3a7220099781a28ea54564133b" +checksum = "a6d1565a7c2a320b711308188adf84980013872e579ae2e6abffe8796eb8e6fe" dependencies = [ "anyhow", "bincode", diff --git a/Cargo.toml b/Cargo.toml index b87e85071a..f7c3af674c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,7 +77,7 @@ version = "1.5.3" version = "0.7.6" [dependencies.snarkvm-curves] -version = "0.7.8" +version = "0.7.9" default-features = false [dependencies.snarkvm-gadgets] diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index 013630af82..a61e03c12b 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -57,7 +57,7 @@ version = "1.5.3" version = "0.4" [dependencies.snarkvm-curves] -version = "0.7.8" +version = "0.7.9" default-features = false [dependencies.snarkvm-fields] diff --git a/state/Cargo.toml b/state/Cargo.toml index c84a45b0d8..f57fbdbc1f 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -29,7 +29,7 @@ version = "1.5.3" version = "0.7.6" [dependencies.snarkvm-curves] -version = "0.7.8" +version = "0.7.9" default-features = false [dependencies.snarkvm-dpc] diff --git a/synthesizer/Cargo.toml b/synthesizer/Cargo.toml index cf681a35db..a4f2280b6b 100644 --- a/synthesizer/Cargo.toml +++ b/synthesizer/Cargo.toml @@ -18,7 +18,7 @@ license = "GPL-3.0" edition = "2018" [dependencies.snarkvm-curves] -version = "0.7.8" +version = "0.7.9" default-features = false [dependencies.snarkvm-fields] From 957d2ef62d314e49fdf2291df836094929d284d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Aug 2021 10:19:17 +0000 Subject: [PATCH 06/17] Bump anyhow from 1.0.42 to 1.0.43 Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.42 to 1.0.43. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.42...1.0.43) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f109d381e2..973892613c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.42" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" +checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" [[package]] name = "arrayvec" From 110b05bfc2c35fcc5469aa5978a530fecefa681a Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 16 Aug 2021 10:11:52 -0700 Subject: [PATCH 07/17] [RFC] Improve title as suggested by Jon. --- docs/rfc/010-native-functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rfc/010-native-functions.md b/docs/rfc/010-native-functions.md index 3760e5478b..097474efd1 100644 --- a/docs/rfc/010-native-functions.md +++ b/docs/rfc/010-native-functions.md @@ -1,4 +1,4 @@ -# Leo RFC 010: Native Functions +# Leo RFC 010: Improved Native Functions ## Authors @@ -17,7 +17,7 @@ DRAFT # Summary -This RFC proposes an approach to handling natively implemented functions ('native functions', for short) in Leo, +This RFC proposes an improved approach to handling natively implemented functions ('native functions', for short) in Leo, that is functions implemented not via Leo code but (in essence) via Rust code. Currently there is just one such function, namely BLAKE2s. The scope of this proposal is limited to native functions defined by the developers of Leo itself, From 16daa63dea7294c6f5c2e85b6b4cb09efe8becde Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 16 Aug 2021 10:19:16 -0700 Subject: [PATCH 08/17] [RFC] Extend native functions RFC based on discussion with Jon. --- docs/rfc/010-native-functions.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/rfc/010-native-functions.md b/docs/rfc/010-native-functions.md index 097474efd1..4d26baf0cc 100644 --- a/docs/rfc/010-native-functions.md +++ b/docs/rfc/010-native-functions.md @@ -179,6 +179,8 @@ This should help support richer standard/core libraries for Leo. # Alternatives +## Programmatic Generation + Instead of storing declarations of native functions in standard/core files as proposed above, we could programmatically generate them as currently done for BLAKE2s. Macros may be used to generate families of similar function declarations. @@ -191,5 +193,22 @@ We could think of splitting the non-native and native functions of `Point2D`: the former in a Leo file, and the latter programmatically added. Again, this looks more complicated than just declaring native funcions in Leo files. -In summary, accommodating native functions in Leo standard/core file -should be doable with mild and possibly simplifying changes to the current Leo compiler. +## Leo Code in Rust Files + +It has been pointed out that it would be beneficial to have +both the Leo code (for the non-native functions) +and the Rust code (for the native functions) +in the same place (i.e. file). +This is not possible if the non-native code is in a Leo file, because Leo files cannot contain Rust code +(and there is no plan to allow that, i.e. no inline Rust code). + +However, we can turn things around and leverage Rust's macro system to accommodate Leo code in Rust files. +That is, we can have Rust files that include both the non-native Leo code, +written as Leo code (with some surrounding macro call or something like that), +along with the Rust code that implements the naive functions. + +This may turn out to be in fact the preferred design in the end, +as it combines the advantage of writing non-native code in Leo +with the advantage of having native and non-native code in the same place. +In that case, we will revise this RFC to swap this design proposal with the one in the main section, +moving the proposal for Leo files to this section as an alternative. \ No newline at end of file From 1bc19d8b1c18be2d0972fd8ac62b818a583864d4 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 16 Aug 2021 10:22:04 -0700 Subject: [PATCH 09/17] [RFC] Extend the native functions RFC a bit more. Explicate how the initially proposed design is consistent with Java, and how the native implementations live in separate files in that design. This better paves the way to the more recent variant of this proposal, currently discussed under alternatives but that may be eventually "swapped" if that's also the rest of the team's consensus. --- docs/rfc/010-native-functions.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/rfc/010-native-functions.md b/docs/rfc/010-native-functions.md index 4d26baf0cc..17b28d6440 100644 --- a/docs/rfc/010-native-functions.md +++ b/docs/rfc/010-native-functions.md @@ -166,6 +166,10 @@ The compiler must know a mapping from native functions in the standard/core libr to the R1CS gadgets that implement them, so it should be just a matter of selecting the appropriate one. Some of this logic must be already present, in order to detect and select the BLAkE2s gadget. +This approach is used in Java, where Java files may declare certain methods as `native`, +without a body but with a declaration of input and output types. +The actual native implementations, i.e. the native method bodies live in different files, as they are written in C. + # Drawbacks This does not seem to bring any drawbacks. From 6e264b86ef9b05ef6a09869567cef6b55fde2e23 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 16 Aug 2021 10:44:10 -0700 Subject: [PATCH 10/17] [RFC] Extend bit/byte conversion RFC. Add an alternative in which we go to methods directly. This seems more likely at this point, given that we seem to have a fairly simple and quick way to support methods on scalar types that does not involve turning scalar types into circuit types. --- docs/rfc/009-bit-byte-conversions.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/rfc/009-bit-byte-conversions.md b/docs/rfc/009-bit-byte-conversions.md index 513b408b94..586b6c40f8 100644 --- a/docs/rfc/009-bit-byte-conversions.md +++ b/docs/rfc/009-bit-byte-conversions.md @@ -263,3 +263,14 @@ such as `u64_to_u16s_le`, which would turn a `u64` into a `[u16; 4]`. In general, it makes sense to convert between `uN` or `iN` and `[uM; P]` when `N == M * P`. If Leo were extended with types `uN` and `iN` for all positive `N` as proposed elsewhere, there could be a family of all such conversions. + +## Methods Directly + +Given that we eventually plan to use methods on scalar types for these conversions, +it may make sense to do that right away. +This is predicated on having support for methods on scalar types, +for which a separate RFC is in the works. + +If we decide for this approach, we will revise the above proposal to reflect that. +The concepts and (essential) names and input/output types remain unchanged, +but the conversions are packaged in slightly different form. From 60478864460e9a880a72e57c2b90d5779c1572b8 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 16 Aug 2021 10:48:24 -0700 Subject: [PATCH 11/17] [RFC] Extend bit/byte conversion RFC. Add a paragraph clarifying what an adequate implementation strategy could be. In any case, we are likely to go with methods on scalar types directly. --- docs/rfc/009-bit-byte-conversions.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/rfc/009-bit-byte-conversions.md b/docs/rfc/009-bit-byte-conversions.md index 586b6c40f8..ff3b4eb51d 100644 --- a/docs/rfc/009-bit-byte-conversions.md +++ b/docs/rfc/009-bit-byte-conversions.md @@ -203,6 +203,14 @@ function i128_from_bytes_le(x: [u8; 16]) -> i128; function i128_from_bytes_be(x: [u8; 16]) -> i128; ``` +## Handling of the Native Functions + +Given the relatively large number and regular structure of the functions above, +it makes sense to generate them programmatically (e.g. via Rust macros), +rather than enumerating all of them explicitly in the implementation. +It may also makes sense, at R1CS generation time, +to use generated or suitably parameterized code to recognize them and turn them into the corresponding gadgets. + ## Transition to Methods Once a separate proposal for adding methods to Leo scalar types is realized, From c140e666a56ad78d01bc60920efa7e4d939b3c19 Mon Sep 17 00:00:00 2001 From: gluaxspeed Date: Mon, 16 Aug 2021 11:38:01 -0700 Subject: [PATCH 12/17] make suggested changes, also renumber as it would conflict with 009 bits/bytes --- ...nd-methods.md => 011-scalar-type-accesses-and-methods.md} | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) rename docs/rfc/{009-scalar-type-accesses-and-methods.md => 011-scalar-type-accesses-and-methods.md} (90%) diff --git a/docs/rfc/009-scalar-type-accesses-and-methods.md b/docs/rfc/011-scalar-type-accesses-and-methods.md similarity index 90% rename from docs/rfc/009-scalar-type-accesses-and-methods.md rename to docs/rfc/011-scalar-type-accesses-and-methods.md index d359dd715b..02b1fb731d 100644 --- a/docs/rfc/009-scalar-type-accesses-and-methods.md +++ b/docs/rfc/011-scalar-type-accesses-and-methods.md @@ -1,4 +1,4 @@ -# Leo RFC 009: Scalar Type Accesses And Methods +# Leo RFC 011: Scalar Type Accesses And Methods ## Authors @@ -52,11 +52,12 @@ postfix-expression = primary-expression / identifier function-arguments / postfix-expression "." identifier function-arguments / named-type "::" identifier function-arguments ; this used to be a circuit-type + / named-type "::" identifier ; this is new to allow static members on / postfix-expression "[" expression "]" / postfix-expression "[" [expression] ".." [expression] "]" ``` -Now methods and static members would be first-class citizens of scalar types and their values. For example, in the following could be done: +Now methods and static members would be first-class citizens of scalar types and their values. For example, the following could be done: ```ts let x = 1u8.to_bits(); // A method call on on a scalar value itself From 80e2b14c8cd316ed23c9658f6a5a013379d7e755 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 16 Aug 2021 18:06:27 -0700 Subject: [PATCH 13/17] [ABNF] Fix rule for conditional expressions. The test of the expression should have been a disjunctive expression. This was an oversight when the rules were written. --- grammar/abnf-grammar.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grammar/abnf-grammar.txt b/grammar/abnf-grammar.txt index e25a8aef02..845c4a1530 100644 --- a/grammar/abnf-grammar.txt +++ b/grammar/abnf-grammar.txt @@ -871,7 +871,7 @@ disjunctive-expression = conjunctive-expression ; Finally we have conditional expressions. conditional-expression = disjunctive-expression - / conditional-expression + / disjunctive-expression "?" expression ":" conditional-expression From 30da9d6e1ce93bc0eaf9511425c7ee21730539c7 Mon Sep 17 00:00:00 2001 From: Alessandro Coglio Date: Mon, 16 Aug 2021 18:07:26 -0700 Subject: [PATCH 14/17] [ABNF] Re-generate the markdown file. --- grammar/README.md | 60 +++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/grammar/README.md b/grammar/README.md index 13bbc6de82..0067d1eab3 100644 --- a/grammar/README.md +++ b/grammar/README.md @@ -466,7 +466,7 @@ described above. newline = line-feed / carriage-return / carriage-return line-feed ``` -Go to: _[carriage-return](#user-content-carriage-return), [line-feed](#user-content-line-feed)_; +Go to: _[line-feed](#user-content-line-feed), [carriage-return](#user-content-carriage-return)_; Line terminators form whitespace, along with spaces and horizontal tabs. @@ -476,7 +476,7 @@ Line terminators form whitespace, along with spaces and horizontal tabs. whitespace = space / horizontal-tab / newline ``` -Go to: _[horizontal-tab](#user-content-horizontal-tab), [newline](#user-content-newline), [space](#user-content-space)_; +Go to: _[space](#user-content-space), [horizontal-tab](#user-content-horizontal-tab), [newline](#user-content-newline)_; There are two kinds of comments in Leo, as in other languages. @@ -494,7 +494,7 @@ the ones used in the Java language reference. comment = block-comment / end-of-line-comment ``` -Go to: _[end-of-line-comment](#user-content-end-of-line-comment), [block-comment](#user-content-block-comment)_; +Go to: _[block-comment](#user-content-block-comment), [end-of-line-comment](#user-content-end-of-line-comment)_; @@ -521,7 +521,7 @@ rest-of-block-comment-after-star = "/" / not-star-or-slash rest-of-block-comment ``` -Go to: _[not-star-or-slash](#user-content-not-star-or-slash), [rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star)_; +Go to: _[rest-of-block-comment](#user-content-rest-of-block-comment), [rest-of-block-comment-after-star](#user-content-rest-of-block-comment-after-star), [not-star-or-slash](#user-content-not-star-or-slash)_; @@ -589,7 +589,7 @@ lowercase-letter = %x61-7A ; a-z letter = uppercase-letter / lowercase-letter ``` -Go to: _[uppercase-letter](#user-content-uppercase-letter), [lowercase-letter](#user-content-lowercase-letter)_; +Go to: _[lowercase-letter](#user-content-lowercase-letter), [uppercase-letter](#user-content-uppercase-letter)_; The following rules defines (ASCII) decimal, octal, and hexadecimal digits. @@ -762,7 +762,7 @@ and Unicode escapes with one to six hexadecimal digits character-literal = single-quote character-literal-element single-quote ``` -Go to: _[single-quote](#user-content-single-quote), [character-literal-element](#user-content-character-literal-element)_; +Go to: _[character-literal-element](#user-content-character-literal-element), [single-quote](#user-content-single-quote)_; @@ -773,7 +773,7 @@ character-literal-element = not-single-quote-or-backslash / unicode-character-escape ``` -Go to: _[not-single-quote-or-backslash](#user-content-not-single-quote-or-backslash), [ascii-character-escape](#user-content-ascii-character-escape), [unicode-character-escape](#user-content-unicode-character-escape), [simple-character-escape](#user-content-simple-character-escape)_; +Go to: _[unicode-character-escape](#user-content-unicode-character-escape), [not-single-quote-or-backslash](#user-content-not-single-quote-or-backslash), [simple-character-escape](#user-content-simple-character-escape), [ascii-character-escape](#user-content-ascii-character-escape)_; @@ -828,7 +828,7 @@ simple-character-escape = single-quote-escape / null-character-escape ``` -Go to: _[carriage-return-escape](#user-content-carriage-return-escape), [horizontal-tab-escape](#user-content-horizontal-tab-escape), [null-character-escape](#user-content-null-character-escape), [double-quote-escape](#user-content-double-quote-escape), [single-quote-escape](#user-content-single-quote-escape), [backslash-escape](#user-content-backslash-escape), [line-feed-escape](#user-content-line-feed-escape)_; +Go to: _[carriage-return-escape](#user-content-carriage-return-escape), [horizontal-tab-escape](#user-content-horizontal-tab-escape), [double-quote-escape](#user-content-double-quote-escape), [backslash-escape](#user-content-backslash-escape), [null-character-escape](#user-content-null-character-escape), [single-quote-escape](#user-content-single-quote-escape), [line-feed-escape](#user-content-line-feed-escape)_; @@ -864,7 +864,7 @@ string-literal-element = not-double-quote-or-backslash / unicode-character-escape ``` -Go to: _[ascii-character-escape](#user-content-ascii-character-escape), [unicode-character-escape](#user-content-unicode-character-escape), [simple-character-escape](#user-content-simple-character-escape), [not-double-quote-or-backslash](#user-content-not-double-quote-or-backslash)_; +Go to: _[not-double-quote-or-backslash](#user-content-not-double-quote-or-backslash), [simple-character-escape](#user-content-simple-character-escape), [unicode-character-escape](#user-content-unicode-character-escape), [ascii-character-escape](#user-content-ascii-character-escape)_; The ones above are all the atomic literals @@ -884,7 +884,7 @@ atomic-literal = untyped-literal / string-literal ``` -Go to: _[signed-literal](#user-content-signed-literal), [untyped-literal](#user-content-untyped-literal), [product-group-literal](#user-content-product-group-literal), [unsigned-literal](#user-content-unsigned-literal), [character-literal](#user-content-character-literal), [string-literal](#user-content-string-literal), [field-literal](#user-content-field-literal), [boolean-literal](#user-content-boolean-literal), [address-literal](#user-content-address-literal)_; +Go to: _[field-literal](#user-content-field-literal), [untyped-literal](#user-content-untyped-literal), [address-literal](#user-content-address-literal), [unsigned-literal](#user-content-unsigned-literal), [character-literal](#user-content-character-literal), [boolean-literal](#user-content-boolean-literal), [signed-literal](#user-content-signed-literal), [string-literal](#user-content-string-literal), [product-group-literal](#user-content-product-group-literal)_; After defining the (mostly) alphanumeric tokens above, @@ -928,7 +928,7 @@ token = keyword / symbol ``` -Go to: _[identifier](#user-content-identifier), [keyword](#user-content-keyword), [symbol](#user-content-symbol), [package-name](#user-content-package-name), [annotation-name](#user-content-annotation-name), [atomic-literal](#user-content-atomic-literal)_; +Go to: _[identifier](#user-content-identifier), [symbol](#user-content-symbol), [keyword](#user-content-keyword), [atomic-literal](#user-content-atomic-literal), [package-name](#user-content-package-name), [annotation-name](#user-content-annotation-name)_; Tokens, comments, and whitespace are lexemes, i.e. lexical units. @@ -995,7 +995,7 @@ group-type = %s"group" arithmetic-type = integer-type / field-type / group-type ``` -Go to: _[integer-type](#user-content-integer-type), [field-type](#user-content-field-type), [group-type](#user-content-group-type)_; +Go to: _[field-type](#user-content-field-type), [integer-type](#user-content-integer-type), [group-type](#user-content-group-type)_; The arithmetic types, along with the boolean, address, and character types, @@ -1021,7 +1021,7 @@ character-type = %s"char" scalar-type = boolean-type / arithmetic-type / address-type / character-type ``` -Go to: _[character-type](#user-content-character-type), [arithmetic-type](#user-content-arithmetic-type), [boolean-type](#user-content-boolean-type), [address-type](#user-content-address-type)_; +Go to: _[boolean-type](#user-content-boolean-type), [arithmetic-type](#user-content-arithmetic-type), [character-type](#user-content-character-type), [address-type](#user-content-address-type)_; Circuit types are denoted by identifiers and the keyword `Self`. @@ -1038,7 +1038,7 @@ self-type = %s"Self" circuit-type = identifier / self-type ``` -Go to: _[identifier](#user-content-identifier), [self-type](#user-content-self-type)_; +Go to: _[self-type](#user-content-self-type), [identifier](#user-content-identifier)_; A tuple type consists of zero, two, or more component types. @@ -1082,7 +1082,7 @@ i.e. types whose values contain (sub-)values aggregate-type = tuple-type / array-type / circuit-type ``` -Go to: _[circuit-type](#user-content-circuit-type), [tuple-type](#user-content-tuple-type), [array-type](#user-content-array-type)_; +Go to: _[array-type](#user-content-array-type), [tuple-type](#user-content-tuple-type), [circuit-type](#user-content-circuit-type)_; Scalar and aggregate types form all the types. @@ -1128,7 +1128,7 @@ A literal is either an atomic one or an affine group literal. literal = atomic-literal / affine-group-literal ``` -Go to: _[affine-group-literal](#user-content-affine-group-literal), [atomic-literal](#user-content-atomic-literal)_; +Go to: _[atomic-literal](#user-content-atomic-literal), [affine-group-literal](#user-content-affine-group-literal)_; The following rule is not directly referenced in the rules for expressions @@ -1170,7 +1170,7 @@ primary-expression = identifier / circuit-expression ``` -Go to: _[array-expression](#user-content-array-expression), [expression](#user-content-expression), [circuit-expression](#user-content-circuit-expression), [identifier](#user-content-identifier), [tuple-expression](#user-content-tuple-expression), [literal](#user-content-literal)_; +Go to: _[tuple-expression](#user-content-tuple-expression), [expression](#user-content-expression), [circuit-expression](#user-content-circuit-expression), [identifier](#user-content-identifier), [array-expression](#user-content-array-expression), [literal](#user-content-literal)_; Tuple expressions construct tuples. @@ -1318,7 +1318,7 @@ postfix-expression = primary-expression / postfix-expression "[" [expression] ".." [expression] "]" ``` -Go to: _[identifier](#user-content-identifier), [circuit-type](#user-content-circuit-type), [function-arguments](#user-content-function-arguments), [natural](#user-content-natural), [primary-expression](#user-content-primary-expression), [expression](#user-content-expression), [postfix-expression](#user-content-postfix-expression)_; +Go to: _[function-arguments](#user-content-function-arguments), [primary-expression](#user-content-primary-expression), [identifier](#user-content-identifier), [postfix-expression](#user-content-postfix-expression), [circuit-type](#user-content-circuit-type), [expression](#user-content-expression), [natural](#user-content-natural)_; Unary operators have the highest operator precedence. @@ -1346,7 +1346,7 @@ exponential-expression = unary-expression / unary-expression "**" exponential-expression ``` -Go to: _[unary-expression](#user-content-unary-expression), [exponential-expression](#user-content-exponential-expression)_; +Go to: _[exponential-expression](#user-content-exponential-expression), [unary-expression](#user-content-unary-expression)_; Next in precedence come multiplication and division, both left-associative. @@ -1428,12 +1428,12 @@ Finally we have conditional expressions. ```abnf conditional-expression = disjunctive-expression - / conditional-expression + / disjunctive-expression "?" expression ":" conditional-expression ``` -Go to: _[disjunctive-expression](#user-content-disjunctive-expression), [expression](#user-content-expression), [conditional-expression](#user-content-conditional-expression)_; +Go to: _[conditional-expression](#user-content-conditional-expression), [disjunctive-expression](#user-content-disjunctive-expression), [expression](#user-content-expression)_; Those above are all the expressions. @@ -1466,7 +1466,7 @@ statement = expression-statement / block ``` -Go to: _[loop-statement](#user-content-loop-statement), [assignment-statement](#user-content-assignment-statement), [variable-declaration](#user-content-variable-declaration), [expression-statement](#user-content-expression-statement), [conditional-statement](#user-content-conditional-statement), [block](#user-content-block), [console-statement](#user-content-console-statement), [return-statement](#user-content-return-statement), [constant-declaration](#user-content-constant-declaration)_; +Go to: _[constant-declaration](#user-content-constant-declaration), [conditional-statement](#user-content-conditional-statement), [expression-statement](#user-content-expression-statement), [return-statement](#user-content-return-statement), [console-statement](#user-content-console-statement), [block](#user-content-block), [loop-statement](#user-content-loop-statement), [assignment-statement](#user-content-assignment-statement), [variable-declaration](#user-content-variable-declaration)_; @@ -1509,7 +1509,7 @@ variable-declaration = %s"let" identifier-or-identifiers [ ":" type ] "=" expression ";" ``` -Go to: _[type](#user-content-type), [identifier-or-identifiers](#user-content-identifier-or-identifiers), [expression](#user-content-expression)_; +Go to: _[identifier-or-identifiers](#user-content-identifier-or-identifiers), [expression](#user-content-expression), [type](#user-content-type)_; @@ -1563,7 +1563,7 @@ The body is a block. loop-statement = %s"for" identifier %s"in" expression ".." [ "=" ] expression block ``` -Go to: _[expression](#user-content-expression), [block](#user-content-block), [identifier](#user-content-identifier)_; +Go to: _[expression](#user-content-expression), [identifier](#user-content-identifier), [block](#user-content-block)_; An assignment statement is straightforward. @@ -1649,7 +1649,7 @@ annotation = annotation-name [ "(" identifier *( "," identifier ) ")" ] ``` -Go to: _[annotation-name](#user-content-annotation-name), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [annotation-name](#user-content-annotation-name)_; A function declaration defines a function. @@ -1666,7 +1666,7 @@ function-declaration = *annotation %s"function" identifier block ``` -Go to: _[identifier](#user-content-identifier), [function-parameters](#user-content-function-parameters), [type](#user-content-type), [block](#user-content-block)_; +Go to: _[block](#user-content-block), [identifier](#user-content-identifier), [type](#user-content-type), [function-parameters](#user-content-function-parameters)_; @@ -1676,7 +1676,7 @@ function-parameters = self-parameter / function-inputs ``` -Go to: _[self-parameter](#user-content-self-parameter), [function-inputs](#user-content-function-inputs)_; +Go to: _[function-inputs](#user-content-function-inputs), [self-parameter](#user-content-self-parameter)_; @@ -1697,7 +1697,7 @@ Go to: _[function-input](#user-content-function-input)_; function-input = [ %s"const" ] identifier ":" type ``` -Go to: _[type](#user-content-type), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [type](#user-content-type)_; A circuit member variable declaration consists of @@ -1745,7 +1745,7 @@ circuit-declaration = %s"circuit" identifier *member-function-declaration "}" ``` -Go to: _[member-variable-declarations](#user-content-member-variable-declarations), [identifier](#user-content-identifier)_; +Go to: _[identifier](#user-content-identifier), [member-variable-declarations](#user-content-member-variable-declarations)_; An import declaration consists of the `import` keyword @@ -1767,7 +1767,7 @@ by using an explicit package name before the package path. import-declaration = %s"import" package-name "." package-path ";" ``` -Go to: _[package-name](#user-content-package-name), [package-path](#user-content-package-path)_; +Go to: _[package-path](#user-content-package-path), [package-name](#user-content-package-name)_; From d2a4a14cf48ddf5e01583d065b2bb1ace6e4571b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Aug 2021 10:18:37 +0000 Subject: [PATCH 15/17] Bump snarkvm-dpc from 0.7.8 to 0.7.9 Bumps [snarkvm-dpc](https://github.com/AleoHQ/snarkVM) from 0.7.8 to 0.7.9. - [Release notes](https://github.com/AleoHQ/snarkVM/releases) - [Commits](https://github.com/AleoHQ/snarkVM/compare/v0.7.8...v0.7.9) --- updated-dependencies: - dependency-name: snarkvm-dpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 32 ++++++++++++++++---------------- compiler/Cargo.toml | 2 +- state/Cargo.toml | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14483a97e6..468ea90f2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2428,9 +2428,9 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "snarkvm-algorithms" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40caa98abd0a874a003d844d6a73562020fb5fa976daa14055f030d9803430b7" +checksum = "3534da2cfa71894e4d28c5dcaf9f9c5c94315904c4ace6c86419a8f2ff8b1641" dependencies = [ "anyhow", "bitvec", @@ -2485,9 +2485,9 @@ dependencies = [ [[package]] name = "snarkvm-dpc" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1588a3d2f38307bd64838cf1761d8cef485461e5224831c9b9df11a1fa9864e7" +checksum = "c922bb690fbe9c5919f67f2d887452376339a36bf5ffb50dc6b00d58a5650284" dependencies = [ "anyhow", "base58", @@ -2533,9 +2533,9 @@ dependencies = [ [[package]] name = "snarkvm-gadgets" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b0cd11387a572f9a1c318c1d446dd46e0522c9be7681b8d6af6882d20880fd" +checksum = "3138cfcaaa27e53cabc7a4fc596b3b0abb47c3cb46fee496e3ac7ce2cd07df9d" dependencies = [ "derivative", "digest 0.9.0", @@ -2553,9 +2553,9 @@ dependencies = [ [[package]] name = "snarkvm-marlin" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206d633d6299dfb4f52640a3188567462dbf1f207de70cbb829707c07858c7e6" +checksum = "12e6987cde7b734415afc7afe58a038d224393842ad5dfaba728a601c5c5473d" dependencies = [ "blake2", "derivative", @@ -2577,9 +2577,9 @@ dependencies = [ [[package]] name = "snarkvm-parameters" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f5c4d4233a623c46c483296aa24bf4d95a5f3344c669ce4f2956467fe6ea904" +checksum = "506cbbbfe27acb4d4e8dd15e49b430dbfb920fd680cfe1c69ab87542083d0422" dependencies = [ "curl", "hex", @@ -2590,9 +2590,9 @@ dependencies = [ [[package]] name = "snarkvm-polycommit" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b5ca8d560cb6f49d9de9b4a955778cc14563b0a381c56db48ea6171788f30d4" +checksum = "c23a7fa2aab25aa6fc3b7fb27b3d639936725a5c29b29936d1530b64bd011e67" dependencies = [ "derivative", "digest 0.9.0", @@ -2609,15 +2609,15 @@ dependencies = [ [[package]] name = "snarkvm-profiler" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cb28d79c59db77774484dbc0f4e876dc8604085d8d7f43eee1b813ec0614b4" +checksum = "f7d80cc343b9e19e0f38582fa7e17e6263c4c7449122cf9a606279567ff33d71" [[package]] name = "snarkvm-r1cs" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e3b7acea34af74dbe5dea056714a9f3c9b1029a9ac888595c96a6e3c676e6" +checksum = "537f2123c7da8a9d3482523156318479790c41e390d33f6936b89a3ed9eee0a8" dependencies = [ "cfg-if 1.0.0", "fxhash", diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml index a61e03c12b..df5e5d65a8 100644 --- a/compiler/Cargo.toml +++ b/compiler/Cargo.toml @@ -65,7 +65,7 @@ version = "0.7.7" default-features = false [dependencies.snarkvm-dpc] -version = "0.7.8" +version = "0.7.9" default-features = false [dependencies.snarkvm-gadgets] diff --git a/state/Cargo.toml b/state/Cargo.toml index f57fbdbc1f..353dfd2199 100644 --- a/state/Cargo.toml +++ b/state/Cargo.toml @@ -33,7 +33,7 @@ version = "0.7.9" default-features = false [dependencies.snarkvm-dpc] -version = "0.7.8" +version = "0.7.9" features = [ "testnet1" ] [dependencies.snarkvm-utilities] From b6d9db20be1a23b2c071eed470a57c8beadd2271 Mon Sep 17 00:00:00 2001 From: yangvenli Date: Tue, 17 Aug 2021 15:47:16 +0300 Subject: [PATCH 16/17] fixes recursive imports issue --- imports/src/parser/import_parser.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/imports/src/parser/import_parser.rs b/imports/src/parser/import_parser.rs index c8fcfdf43a..01b7702dd8 100644 --- a/imports/src/parser/import_parser.rs +++ b/imports/src/parser/import_parser.rs @@ -55,10 +55,9 @@ impl<'a> ImportResolver<'a> for ImportParser<'a> { if let Some(program) = self.imports.get(&full_path) { return Ok(Some(program.clone())); } - let mut imports = Self::default(); let path = self.program_path.clone(); - self.partial_imports.insert(full_path.clone()); + let mut imports = self.clone(); // Self::default() was previously let program = imports .parse_package(context, path, package_segments, span) .map_err(|x| -> AsgConvertError { x.into() })?; From f258c5bde55e7b45bf65760f199f37f3a9d0a59b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Aug 2021 10:17:46 +0000 Subject: [PATCH 17/17] Bump serde_yaml from 0.8.17 to 0.8.18 Bumps [serde_yaml](https://github.com/dtolnay/serde-yaml) from 0.8.17 to 0.8.18. - [Release notes](https://github.com/dtolnay/serde-yaml/releases) - [Commits](https://github.com/dtolnay/serde-yaml/compare/0.8.17...0.8.18) --- updated-dependencies: - dependency-name: serde_yaml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 468ea90f2d..6884fdf78e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2361,9 +2361,9 @@ dependencies = [ [[package]] name = "serde_yaml" -version = "0.8.17" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" +checksum = "039ba818c784248423789eec090aab9fb566c7b94d6ebbfa1814a9fd52c8afb2" dependencies = [ "dtoa", "linked-hash-map",