Releases: ProvableHQ/leo
v4.0.2
What's Changed
- feat(parser/passes): support multi-segment locator paths for external submodules by @mohammadfawaz in #29338
- bump version to
v4.0.2on the release branch by @mohammadfawaz in #29365
Full Changelog: v4.0.1...v4.0.2
v4.0.1
What's Changed
- Fix publishing issues by @mohammadfawaz in #29277
- Update examples to latest (4.0.0 version) by @mohammadfawaz in #29278
- Return normal error instead of panic on unknown consensus version by @IGI-111 in #29286
- [Bug Fix] Devnode private key check by @Roee-87 in #29279
- Fix compiler panic by @IGI-111 in #29290
- fix array in mapping issue by @mohammadfawaz in #29291
- fix: Fail on missing expectation files. Rename
recordvariable instatic_external_futuretest. by @mitchmindtree in #29281 - Accept dyn record arguments by looking up interface records (not program records) by @mohammadfawaz in #29296
- Compare modes semantically instead of literally by @IGI-111 in #29300
- Check vector type usage by @IGI-111 in #29247
- Stubs inserted in the wrong order in monomorphization by @mohammadfawaz in #29299
- Fix panic on out-of-bounds tuple access in final block by @mohammadfawaz in #29310
- Fix compiler panic when destructuring a non-tuple value by @mohammadfawaz in #29311
- Fix panic on undefined type in dynamic intrinsic type parameters by @mohammadfawaz in #29312
- Reject const generics in non-inlinable function contexts by @mohammadfawaz in #29313
- Fix panic on unsuffixed integer literal in dynamic intrinsic arguments by @mohammadfawaz in #29317
- Fix panics when comparing unit-type expressions by @mohammadfawaz in #29318
- Add
--network-retriesflag with exponential backoff for transient network failures by @mohammadfawaz in #29289 - fix(package): remove topo order requirement for .aleo deps in
program.jsonby @mitchmindtree in #29320 - Fix false-positive interface conformance errors and panic on array-length expressions in interface prototypes by @mohammadfawaz in #29298
- interfaces in libraries by @mohammadfawaz in #29249
- Allow
signaturetype in storage by @mohammadfawaz in #29321 v4.0.1release by @mohammadfawaz in #29322
Full Changelog: v4.0.0...v4.0.1
v4.0.0
Leo 4.0 is a major release that streamlines the language model, introduces first-class library and interface support, and ships full dynamic dispatch. The on-chain execution model has been simplified, the syntax made more consistent, and the foundation laid for large-scale program composition on Aleo.
Unified fn Syntax
The biggest surface-level change in 4.0 is the unification of all function declarations under a single fn keyword. The old transition, function, inline, and async transition keywords are gone.
| Leo 3.5 | Leo 4.0 |
|---|---|
transition foo() |
fn foo() inside program {} |
async transition foo() -> Future |
fn foo() -> Final inside program {} |
function foo() |
fn foo() outside program {} |
inline foo() |
fn foo() outside program {} |
async function foo() |
final { ... } block |
async { ... } |
final { ... } |
f.await() |
f.run() |
Future |
Final |
@test script foo() |
@test fn foo() |
Entry functions live inside program {} and form the public interface of the program. Helper functions live outside program {} and cannot produce records. Functions that need on-chain logic include a final { } block — everything inside it runs atomically on the network.
// Helper function — outside program {}
fn add(a: u64, b: u64) -> u64 {
return a + b;
}
program counter.aleo {
mapping tally: address => u64;
// Entry function — inside program {}
fn increment(amount: u64) -> Final {
let sum: u64 = add(tally[self.caller], amount);
return final {
// On-chain logic
tally[self.caller] += amount;
};
}
}Interfaces
Leo 4.0 introduces interfaces — a compile-time mechanism for defining structural contracts over programs. An interface declares the functions, records, mappings, and storage that a conforming program must provide. Programs opt in with : InterfaceName.
// Declared outside program {}
interface Transfer {
record Token;
fn transfer(input: Token, to: address, amount: u64) -> Token;
}
interface Pausable {
fn pause();
fn unpause();
}
// Implements both interfaces
program my_token.aleo : Transfer + Pausable {
record Token {
owner: address,
amount: u64,
}
fn transfer(input: Token, to: address, amount: u64) -> Token {
return Token { owner: to, amount };
}
fn pause() { ... }
fn unpause() { ... }
}Interfaces support inheritance — an interface can extend one or more other interfaces:
interface Token : Transfer + Balances {
fn mint(to: address, amount: u64);
}Record requirements in interfaces can be structural (with optional .. to allow extra fields):
interface HasMemo {
record Rec { owner: address, memo: u64, .. }
}Dynamic Dispatch
Programs can now call other programs without knowing their concrete identity at compile time. Dynamic dispatch uses the Interface@(target)::method(args) syntax, where target is a value of the new identifier type. Identifier literals use single-quote syntax.
interface Counter {
fn increment(amount: u64) -> u64;
}
program dispatcher.aleo {
fn run(target: identifier, amount: u64) -> u64 {
// Calls `increment` on whichever program `target` names
return Counter@(target)::increment(amount);
}
}
// Calling with a literal identifier
let target: identifier = 'my_counter';Records passed through dynamic calls are typed as dyn record — a record whose structure is not known at compile time. Fields can be accessed by name and are resolved at runtime.
fn get_memo(rec: dyn record) -> u64 {
return rec.memo; // Fails at runtime if the field is absent
}Leo Libraries
Programs can now be packaged as libraries — reusable collections of constants, structs, and functions with no on-chain footprint. Libraries are created with leo new --library, use lib.leo instead of main.leo, and contain no program {} block.
// math_utils/src/lib.leo
const PI: field = 3141592653field;
struct Point {
x: i64,
y: i64,
}
fn distance(a: Point, b: Point) -> field {
// ...
}Libraries are referenced by path with :: — no import statement is needed, just a program.json dependency entry:
// Consumer program
fn move_point(p: math_utils::Point, dx: i64) -> math_utils::Point {
return math_utils::Point { x: p.x + dx, y: p.y };
}Libraries support submodules (math_utils::geometry::area) and generic functions (fn dot::[N: u32](a: Vector, b: Vector) -> field). They are fully inlined at compile time.
External Path Separator: / → ::
All external paths now use :: instead of /:
// Leo 3.5
token.aleo/transfer(to, amount)
// Leo 4.0
token.aleo::transfer(to, amount)This applies to external function calls, external storage access (token.aleo::balances), and library item paths.
Removed: Scripts and leo debug
Script functions and leo debug have been removed. In Leo 3.5, @test script functions provided an interactive debugging entrypoint invoked via leo debug. This feature has been retired in 4.0. Tests are now written as @test fn functions inside program {} and run with leo test.
// Leo 3.5 — removed
@test script run() { ... }
// Leo 4.0
program my_program.aleo {
@test fn run() { ... }
}leo test Improvements
- Proof generation is skipped by default.
leo testno longer downloads snarkVM parameters or generates proofs unless--proveis explicitly passed, making test iteration dramatically faster. - Non-zero exit status on failure.
leo testnow correctly exits with a non-zero code when any test fails, enabling proper CI integration.
leo test # Fast — no proof generation
leo test --prove # Full end-to-end proof generationv3.5.0
Leo v3.5.0 — Highlights
Leo v3.5.0 introduces major improvements to the developer workflow, compiler infrastructure, and tooling ecosystem. This release adds formatting support, ABI generation, external storage access, a new devnode command, and major compiler improvements.
leo fmt — Code Formatter
Leo now includes a built-in formatter to automatically format Leo programs.
leo fmtThis formats all .leo files in your project.
Example:
Before
transition main(a:u32,b:u32)->u32{
return a+b;
}After
transition main(a: u32, b: u32) -> u32 {
return a + b;
}JSON ABI Generation
leo build now generates a JSON ABI object that describes the interface of a Leo program. In addition, generating a JSON ABI object directly from a compiled .aleo program is also possible via leo abi:
leo abi program.aleoExample JSON ABI:
{
"program": "child1.aleo",
"structs": [],
"records": [],
"mappings": [],
"storage_variables": [],
"transitions": [
{
"name": "main",
"is_async": false,
"inputs": [
{ "name": "b", "ty": { "Plaintext": { "Primitive": { "UInt": "U32" } } }, "mode": "None" }
],
"outputs": [
{ "ty": { "Plaintext": { "Primitive": { "UInt": "U32" } } }, "mode": "None" }
]
}
]
}JSON ABIs help external tools that want to interface with Leo/Aleo programs, such as SDKs.
leo devnode — Local Development Node
A new command allows developers to quickly spin up a local Aleo devnode.
leo devnodeThis simplifies local testing and removes the need to manually run and configure a node.
External Storage Access
Leo programs can now read storage from external programs.
Example:
let counter: u32? = token.aleo/counter;
let balance: u32? = token.aleo/balance.get(0);CLI Shortcuts
Short commands are now available for common operations:
leo b # build
leo r # run
leo t # testStructured CLI Output
The CLI can now emit structured JSON output:
leo execute --json-output ...Example output:
{
"config": {
"address": "XXXXXX",
"network": "testnet",
"endpoint": "http://localhost:3030",
"consensus_version": 13
},
"program": "test_json_program.aleo",
"function": "main",
"outputs": [
"3u32"
],
"transaction_id": "XXXXXX",
"stats": {
"storage_cost": 1328,
"execution_cost": 0,
"priority_fee": 0,
"total_cost": 1328
},
"broadcast": {
"fee_id": "XXXXXX",
"fee_transaction_id": "XXXXXX",
"confirmed": true
}
}Signature Literals
Leo now supports signature literals and optional signatures.
Example:
let sig: signature = 0xsign1234...;Optional signatures:
let sig: signature? = none;Merged PRs
- [Release] Leo v3.4.0 by @d0cd in #29023
- Add CLI shortcuts for build, run, and test commands by @JoshuaBatty in #29020
- No ledger execution tests by @mohammadfawaz in #29022
- Explicit pass schedule in test framework by @IGI-111 in #29028
- feat: Add a
--disable-update-checkflag to leo by @mitchmindtree in #29026 - ci: Change integration test condition to allow testing on unix by @mitchmindtree in #29032
- Display compiled program size in
leo build,leo deploy, andleo upgradeoutput by @JoshuaBatty in #29033 - Add definition aware late const folding step by @IGI-111 in #29013
- Cache snarkOS binary in CI to avoid 5+ minute rebuild by @JoshuaBatty in #29031
- Enforce usage of latest program edition by @JoshuaBatty in #29027
- Unified intrinsics by @IGI-111 in #29034
- fix: tokenize group/signature/Future paths with regex by @phrwlk in #29046
- Upgrade Rust version and remove some dead files by @mohammadfawaz in #29042
- [Non-functional] Change the syntax tree converter to use a
ConversionContextby @mohammadfawaz in #29047 - Change "struct" to "composite" where appropriate by @mohammadfawaz in #29052
- Explicit intrinsic disambiguation by @IGI-111 in #29048
- perf: reduce cloning in await checker tree nodes by @SashaMalysehko in #29054
- fix: clarify import private key error message by @Fibonacci747 in #29055
- Add
--json-outputflag to save structured CLI output to disk by @JoshuaBatty in #29051 - Rework
Pathrepresentation and early compiler pipeline ordering by @mohammadfawaz in #29060 - Cleanup remnants from code generation refactor by @IGI-111 in #29065
- fix: avoid extra allocation when building record members by @Bashmunta in #29070
- Update all license headers to use 2026 by @mohammadfawaz in #29073
- Upgrade to canary-4.5.0 by @mohammadfawaz in #29069
- Rework program imports + external structs by @mohammadfawaz in #28986
- refactor: reduce redundant type cloning in reconstructor by @radik878 in #29076
- Cleanup Cargo.toml files by @mohammadfawaz in #29075
- Update leo banner by @raychu86 in #29081
- feat(leo-fmt): add formatter crate scaffolding by @JoshuaBatty in #29083
- feat(parser): Add
leo-parser-rowancrate and initial lexer implementation by @mitchmindtree in #29080 - feat: Add ABI Generation, including
leo-abi-typesandleo-abicrates by @mitchmindtree in #29064 - fix: drop
redundant filter_mapin remove_unreachable by @GarmashAlex in #29072 - perf: avoid Vec allocation in async finalize lookup by @phrwlk in #29091
- feat(leo-fmt): implement declaration formatting by @JoshuaBatty in #29094
- External storage accesses by @mohammadfawaz in #29092
- feat(parser-rowan): implement core parsing logic by @mitchmindtree in #29095
- [Feature] Leo Devnode CLI command by @Roee-87 in #29012
- fix: preserve and format HTTP response body in broadcast errors by @JoshuaBatty in #29100
- feat(parser-rowan): implement comprehensive error recovery by @mitchmindtree in #29103
- Deprecate
Locatorexpressions in favor ofPathexpressions by @mohammadfawaz in #29098 - Prepare for
testnet-v3.5.0tag by @mohammadfawaz in #29105 - Update linux and macos release jobs by @mohammadfawaz in #29108
- feat(leo-fmt): implement statement and expression formatting by @JoshuaBatty in #29104
- Add signature literals and support optional signatures by @mohammadfawaz in #29102
- feat(cli): add
leo abicommand for generating ABI from .aleo files by @mitchmindtree in #29116 - refactor(leo-parser): change tests to use
Displayinstead ofSerializeby @mitchmindtree in #29117 - refactor(leo-fmt): switch from
leo-parser-losslesstoleo-parser-rowanby @JoshuaBatty in #29118 - Refactor the CLI testing framework +
leo devnodeenhancements by @mohammadfawaz in #29120 - Surface missing private_key error for leo devnode by @vicsn in #29110
- feat(cli): add leo fmt command by @JoshuaBatty in #29124
- fix(cli): remove duplicate
EnvOptionsflatten indevnodesubcommands by @mitchmindtree in #29126 - Use a prebuilt genesis block for execution tests by @mohammadfawaz in #29121
- [Fix]
--skipoption forleo upgradeand improve spacing for CLI output by @d0cd in #29130 - feat(leo-fmt): add line wrapping at 100-char width by @JoshuaBatty in #29132
- Traverse stubs when calling
fillin WriteTransforming by @mohammadfawaz in #29137 - Some fixes from master and move to canary 4.5.3 by @mohammadfawaz in #29141
- fix(leo-fmt): remaining formatter edge cases from #29127 by @JoshuaBatty in #29142
- fix(leo-fmt): wrap long binary expression chains: release-3.5 by @JoshuaBatty in #29176
- [Fix] Devnet tests after snarkOS v4.5.0. by @d0cd in #29186
New Contributors
- @phrwlk made t...
testnet-v3.5.1
testnet v3.5.1
canary-v3.5.0
What's Changed
- Update linux and macos release jobs by @mohammadfawaz in #29108
- feat(leo-fmt): implement statement and expression formatting by @JoshuaBatty in #29104
- Add signature literals and support optional signatures by @mohammadfawaz in #29102
- feat(cli): add
leo abicommand for generating ABI from .aleo files by @mitchmindtree in #29116 - refactor(leo-parser): change tests to use
Displayinstead ofSerializeby @mitchmindtree in #29117 - refactor(leo-fmt): switch from
leo-parser-losslesstoleo-parser-rowanby @JoshuaBatty in #29118 - Refactor the CLI testing framework +
leo devnodeenhancements by @mohammadfawaz in #29120 - Surface missing private_key error for leo devnode by @vicsn in #29110
- feat(cli): add leo fmt command by @JoshuaBatty in #29124
- fix(cli): remove duplicate
EnvOptionsflatten indevnodesubcommands by @mitchmindtree in #29126 - Use a prebuilt genesis block for execution tests by @mohammadfawaz in #29121
- [Fix]
--skipoption forleo upgradeand improve spacing for CLI output by @d0cd in #29130 - feat(leo-fmt): add line wrapping at 100-char width by @JoshuaBatty in #29132
- Traverse stubs when calling
fillin WriteTransforming by @mohammadfawaz in #29137 - Some fixes from master and move to canary 4.5.3 by @mohammadfawaz in #29141
- fix(leo-fmt): remaining formatter edge cases from #29127 by @JoshuaBatty in #29142
Full Changelog: testnet-v3.5.0...canary-v3.5.0
testnet-v3.5.0
What's Changed
- [Release] Leo v3.3.1 by @d0cd in #28965
- support CONSENSUS_VERSION_HEIGHTS env var in devnet command by @eranrund in #28968
- Don't delete local constants during const propagation and unroll by @IGI-111 in #28970
- Allow empty loops by @IGI-111 in #28975
- Add support for empty arrays by @IGI-111 in #28979
- perf: remove unnecessary clone when reconstructing functions by @Galoretka in #29000
- fix: remove shadowed predeclared code and redundant clear() in interpret() by @Snezhkko in #29003
- Structured code generation by @IGI-111 in #28999
- [Feat] Support
block.timestampby @raychu86 in #28988 - [Fix] Code generation for
*::commit_*core functions. by @d0cd in #28995 - Tidying up the repo a bit by @mohammadfawaz in #29015
- Allow
addressin optionals and storage by @mohammadfawaz in #29005 - Simplify conditional blocks by @IGI-111 in #29004
- A few fixes to options in type checking and option lowering by @mohammadfawaz in #29019
- [Release] Leo v3.4.0 by @d0cd in #29023
- Add CLI shortcuts for build, run, and test commands by @JoshuaBatty in #29020
- No ledger execution tests by @mohammadfawaz in #29022
- Explicit pass schedule in test framework by @IGI-111 in #29028
- feat: Add a
--disable-update-checkflag to leo by @mitchmindtree in #29026 - ci: Change integration test condition to allow testing on unix by @mitchmindtree in #29032
- Display compiled program size in
leo build,leo deploy, andleo upgradeoutput by @JoshuaBatty in #29033 - Add definition aware late const folding step by @IGI-111 in #29013
- Cache snarkOS binary in CI to avoid 5+ minute rebuild by @JoshuaBatty in #29031
- Enforce usage of latest program edition by @JoshuaBatty in #29027
- Unified intrinsics by @IGI-111 in #29034
- fix: tokenize group/signature/Future paths with regex by @phrwlk in #29046
- Upgrade Rust version and remove some dead files by @mohammadfawaz in #29042
- [Non-functional] Change the syntax tree converter to use a
ConversionContextby @mohammadfawaz in #29047 - Change "struct" to "composite" where appropriate by @mohammadfawaz in #29052
- Explicit intrinsic disambiguation by @IGI-111 in #29048
- perf: reduce cloning in await checker tree nodes by @SashaMalysehko in #29054
- fix: clarify import private key error message by @Fibonacci747 in #29055
- Add
--json-outputflag to save structured CLI output to disk by @JoshuaBatty in #29051 - Rework
Pathrepresentation and early compiler pipeline ordering by @mohammadfawaz in #29060 - Cleanup remnants from code generation refactor by @IGI-111 in #29065
- fix: avoid extra allocation when building record members by @Bashmunta in #29070
- Update all license headers to use 2026 by @mohammadfawaz in #29073
- Upgrade to canary-4.5.0 by @mohammadfawaz in #29069
- Rework program imports + external structs by @mohammadfawaz in #28986
- refactor: reduce redundant type cloning in reconstructor by @radik878 in #29076
- Cleanup Cargo.toml files by @mohammadfawaz in #29075
- Update leo banner by @raychu86 in #29081
- feat(leo-fmt): add formatter crate scaffolding by @JoshuaBatty in #29083
- feat(parser): Add
leo-parser-rowancrate and initial lexer implementation by @mitchmindtree in #29080 - feat: Add ABI Generation, including
leo-abi-typesandleo-abicrates by @mitchmindtree in #29064 - fix: drop
redundant filter_mapin remove_unreachable by @GarmashAlex in #29072 - perf: avoid Vec allocation in async finalize lookup by @phrwlk in #29091
- feat(leo-fmt): implement declaration formatting by @JoshuaBatty in #29094
- External storage accesses by @mohammadfawaz in #29092
- feat(parser-rowan): implement core parsing logic by @mitchmindtree in #29095
- [Feature] Leo Devnode CLI command by @Roee-87 in #29012
- fix: preserve and format HTTP response body in broadcast errors by @JoshuaBatty in #29100
- feat(parser-rowan): implement comprehensive error recovery by @mitchmindtree in #29103
- Deprecate
Locatorexpressions in favor ofPathexpressions by @mohammadfawaz in #29098 - Prepare for
testnet-v3.5.0tag by @mohammadfawaz in #29105
New Contributors
- @Galoretka made their first contribution in #29000
- @Snezhkko made their first contribution in #29003
- @mitchmindtree made their first contribution in #29026
- @phrwlk made their first contribution in #29046
- @SashaMalysehko made their first contribution in #29054
- @Fibonacci747 made their first contribution in #29055
- @Bashmunta made their first contribution in #29070
- @radik878 made their first contribution in #29076
- @Roee-87 made their first contribution in #29012
Full Changelog: v3.3.1...testnet-v3.5.0
v3.4.0
Release Notes
Empty arrays and empty loop
Arrays of size 0 and loops over empty ranges are now supported in Leo. While these constructs do not produce any instructions in the compiled Aleo bytecode, they enable more generic or pattern-based programming styles in Leo, especially when writing code that abstracts over sizes, iterates conditionally, or uses compile-time parameters. For example:
inline build_default::[N: u32]() -> [u8; N] {
let xs: [u8; N] = [0u8; N];
// When N = 0 this loop is simply skipped
for i:u32 in 0..N {
xs[i] = 1u8;
}
return xs;
}
let xs = build_default::[0](); // yields []Stability improvements
- Improved identifier validation in Leo, resulting in clearer and more precise error messages, especially when Leo identifiers conflict with reserved Aleo identifiers.
- Fixed an issue where local
constvalues failed to compile correctly when used in loop ranges. - Resolved a crash in the common subexpression elimination optimization pass that occurred for certain patterns of function calls.
Breaking Changes
- The
*hash_native*core functions have been renamed to*hash_to_bits*.
v3.3.1
Patch
- Fixes error in common subexpression elimination.
v3.3.0
Release Notes
Optional Types (T?)
Leo now supports first-class optional types using the T? syntax (e.g., u8?, Foo?, [u64?; 2]).
Optional values can be compared with none, assigned, passed into inline functions, and stored in arrays and structs.
program optionals.aleo {
struct Point { x: u32, y: u32 }
transition main() {
// Optional integers
let x: u8? = 42u8;
let y = x.unwrap(); // Returns 42u8
let z: u8? = none;
let a = z.unwrap_or(99u8); // Returns 99u8
// Array of optionals
let arr: [u16?; 2] = [1u16, none];
let first_val = arr[0].unwrap(); // Returns 1u16
let second_val = arr[1].unwrap_or(0u16); // Returns 0u16
// Optional struct
let p: Point? = none;
let p_val = p.unwrap_or(Point { x: 0u32, y: 0u32 }); // Returns default Point
}
}Type coercion from T to T? is supported in variable definitions, inline function calls, and intermediate expressions.
Explicit unwrapping is required to go from T? → T.
New Storage System
Leo now supports persistent storage variables and storage vectors using the storage keyword.
Storage variables and vectors are declared at program scope, similar to mappings.
program storage_ops.aleo {
struct Point { x: field, y: field }
storage counter: u32; // singleton storage variable
storage points: [Point]; // storage vector of `Point`s
transition main() -> Future {
return async {
counter = 5u32;
let old = counter.unwrap_or(0u32); // returns optional
points.push(Point { x: 1field, y: 2field });
let first = points.get(0u32).unwrap();
points.set(0u32, Point { x: 3field, y: 4field });
counter = none; // unset
}
}
}Storage vector supported operations:
vec.push(10u32); // Push 10u32 at the end of vector `vec`
let x = vec.pop(); // Pop and return the last element of `vec`
let y = vec.get(5); // Get element at index 5
vec.set(3, 5u32); // Set element at index 3 to `5u32`
let y = vec.len(); // Return the number of elements in `vec`
vec.swap_remove(3); // Remove element at index 3 and replace with lastInternally, the compiler rewrites these high-level constructs into mappings and mapping operations.
ECDSA Signature Verification
ECDSA signature verification is now supported with 20 variants covering different hash algorithms and address formats.
// Verify with digest (pre-hashed message)
let valid: bool = ECDSA::verify_digest(sig, addr, digest);
let valid: bool = ECDSA::verify_digest_eth(sig, eth_addr, digest);
// Verify with Keccak256 hashing
let valid: bool = ECDSA::verify_keccak256(sig, addr, msg);
let valid: bool = ECDSA::verify_keccak256_raw(sig, addr, msg);
let valid: bool = ECDSA::verify_keccak256_eth(sig, eth_addr, msg);Also available: keccak384, keccak512, sha3_256, sha3_384, sha3_512.
Parameters:
| Parameter | Type | Description |
|---|---|---|
sig |
[u8; 65] |
ECDSA signature (r, s, v) |
addr |
[u8; 33] or [u8; 20] |
Public key or Ethereum-style address |
digest |
[u8; 32] |
Pre-hashed message |
msg |
Any |
Message to hash and verify |
Raw Hash Operations
Leo now supports raw hash variants. These omit metadata and directly hash input bits, useful for interoperability with external (especially EVM) systems.
Inputs for raw variants of Keccak* and Sha3* must be byte-aligned (number of bits is a multiple of 8).
// Raw hash functions
let h: field = Keccak256::hash_to_field_raw(input);
let h: group = BHP256::hash_to_group_raw(input);
let h: address = Pedersen64::hash_to_address_raw(input);
// Native variants
let bits: [bool; 256] = Keccak256::hash_native(input);
let bits: [bool; 256] = Keccak256::hash_native_raw(input);Available for:
BHP256, BHP512, BHP768, BHP1024, Pedersen64, Pedersen128, Poseidon2, Poseidon4, Poseidon8, Keccak256, Keccak384, Keccak512, SHA3_256, SHA3_384, SHA3_512.
Serialization / Deserialization Operations
Leo now supports serialize and deserialize operations to and from bits, with both metadata-inclusive and raw variants.
The compiler checks that bit sizes match.
// Standard serialization (includes metadata)
let bits: [bool; 58] = Serialize::to_bits(value);
let value: u32 = Deserialize::from_bits::[u32](bits);
// Raw serialization (no metadata)
let bits: [bool; 32] = Serialize::to_bits_raw(value);
let value: u32 = Deserialize::from_bits_raw::[u32](bits);
// Arrays
let bits: [bool; 128] = Serialize::to_bits_raw([1u32, 2u32, 3u32, 4u32]);
let arr: [u32; 4] = Deserialize::from_bits_raw::[[u32; 4]](bits);Bit Lengths
| Type | Raw Bits | Notes |
|---|---|---|
u32 |
32 | |
field |
253 | |
scalar |
251 | |
address |
253 | |
| Non-raw | + metadata overhead |
leo synthesize Command
Generate proving and verifying keys for all transitions in a local or remote Leo program, along with circuit metadata:
leo synthesize credits.aleo --save keys \
--endpoint https://api.explorer.provable.com/v1 \
--network mainnetOutput includes:
- Public inputs
- Variables
- Constraints
- Non-zero entries in matrices
- Circuit ID
- Proving and verifying keys saved to disk
This enables better understanding of program size and key management.
Lossless Syntax Tree Parser
A new lossless syntax tree parser has been added.
While not user-facing yet, it lays the foundation for a future code formatter.
Common Subexpression Elimination (CSE)
New optimization pass reduces bytecode size by eliminating redundant expressions.
Enhanced Error Messages
Error messages now display multiple related source locations.
Example with duplicate struct members:
struct Person {
name: field,
age: u8,
name: field,
}Error:
Error [ETYC0372017]: the name `name` is defined multiple times in struct `Person`
--> src/main.leo:3:9
|
3 | name: field,
| ^^^^^^^^^^^ previous definition here
...
5 | name: field,
| ^^^^^^^^^^^ redefined here
Remaining Stability Improvements
- Various fixes to the interpreter related to hashing correctness
- Fixed broken
leo query committeeendpoint - Validates program names in
leo newagainst reserved SnarkVM keywords - Enforces test isolation for native tests
- Speeds up
leo testby running native tests in parallel - Supports
CheatCode::set_signer("APrivateKey1...")for test signer switching