Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Support native stdlib #201

Merged
merged 37 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
fbfa222
fix: avoid re-instantiate functions/methods
katat Sep 27, 2024
4eaed5b
fix: monomorphized expr shouldn't override existing nodes
katat Oct 5, 2024
10432c3
fmt
katat Oct 9, 2024
0221102
support unsafe/hint attributes
katat Oct 9, 2024
5353d42
fmt
katat Oct 9, 2024
253f4b5
fix: always check the resolved qualified name
katat Oct 10, 2024
64f1758
incorporate native stdlib for testing
katat Sep 27, 2024
be66e55
add int module
katat Sep 27, 2024
6f26d5b
add comparator stdlib
katat Sep 27, 2024
b283046
native bits stdlib
katat Sep 27, 2024
00d230b
move init_stdlib_dep to stdlib
katat Oct 11, 2024
1d2cba7
add bits stdlib
katat Oct 11, 2024
9b94dfb
remove bits builtin
katat Oct 11, 2024
64c2352
download stdlib
katat Oct 11, 2024
3c0b022
add comparator methods for uint8
katat Oct 11, 2024
f54a53c
fmt
katat Oct 11, 2024
5c8918e
remove unused import
katat Oct 11, 2024
18825a3
Fix: Allow struct fields to propagate constants (#204)
katat Oct 22, 2024
ca35175
add uint16/32/64
katat Oct 18, 2024
55f441a
update tests
katat Oct 18, 2024
2b47a8d
fix: remove bit_len from uints
katat Oct 24, 2024
8ef0993
simplify to_bits
katat Oct 24, 2024
1f8826a
add const var STDLIB_DIRECTORY
katat Oct 24, 2024
8834fff
move native stdlib to their own folder
katat Oct 24, 2024
a822a1b
fmt
katat Oct 24, 2024
3f91646
Add u16/32/64 (#206)
katat Oct 24, 2024
c2c78c9
remove deadcode
katat Oct 24, 2024
328ffbf
point to zksecurity repo
katat Oct 24, 2024
7befb6b
Merge remote-tracking branch 'origin/main' into feat/init-stdlib
katat Oct 24, 2024
42a520a
remove deadcode
katat Oct 25, 2024
be8127d
doc bits
katat Oct 25, 2024
665ef2e
use main branch as the release branch for downloading
katat Oct 25, 2024
ab75d85
clean up
katat Oct 25, 2024
34cf5c4
ci: init stdlib from the latest code in pr
katat Oct 25, 2024
4cfb0c5
add docs to stdlib
katat Oct 25, 2024
eb1def1
Support multiplexer (#207)
katat Oct 28, 2024
83e3491
Add MIMC stdlib (#208)
katat Oct 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/snarkjs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ fi
DIR_PATH=$1
CURVE=$2

# Init stdlib in .noname/release/src/stdlib instead of downloading
echo "Overriding stdlib in .noname/release/src/stdlib..."
mkdir -p ~/.noname/release/src/stdlib/ && cp -r /app/noname/src/stdlib/* ~/.noname/release/src/stdlib/
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we should do this manually BTW, we should let noname do it

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is because the CI test wants to test against the latest code, including the stdlib. To ensure the latest code, here overrides the default downloaded version with the code from the PR.


# Ensure the circuit directory exists and is initialized
echo "Initializing a new Noname package..."
noname new --path circuit_noname
Expand Down
132 changes: 90 additions & 42 deletions examples/fixture/asm/kimchi/generic_builtin_bits.asm
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,118 @@
@ public inputs: 1

DoubleGeneric<1>
DoubleGeneric<1,0,-1,0,-1>
DoubleGeneric<1,0,0,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,1,-1>
DoubleGeneric<0,0,-1,1>
DoubleGeneric<1>
DoubleGeneric<1,0,-1>
DoubleGeneric<1,0,-1,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,-1>
DoubleGeneric<0,0,-1,1>
DoubleGeneric<1>
DoubleGeneric<2,0,-1>
DoubleGeneric<1,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,1>
DoubleGeneric<1,1,-1>
DoubleGeneric<1,0,-1,0,-1>
DoubleGeneric<0,0,-1,1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,-1>
DoubleGeneric<0,0,-1,1>
DoubleGeneric<1>
DoubleGeneric<4,0,-1>
DoubleGeneric<1,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,1>
DoubleGeneric<1,1,-1>
DoubleGeneric<1,-1>
DoubleGeneric<0,0,-1,1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,0,0,0,-1>
DoubleGeneric<1,0,0,0,-1>
DoubleGeneric<1,-1>
DoubleGeneric<0,0,-1,1>
DoubleGeneric<1>
DoubleGeneric<1,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,0,0,0,-1>
DoubleGeneric<1,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<2,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,1,-1>
DoubleGeneric<4,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,1,-1>
DoubleGeneric<1,-1>
DoubleGeneric<1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,0,0,0,-1>
DoubleGeneric<1,0,0,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,0,0,0,-1>
DoubleGeneric<1,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<2,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,1,-1>
DoubleGeneric<4,0,-1>
DoubleGeneric<1,1>
DoubleGeneric<1,0,-1,0,1>
DoubleGeneric<1,1,-1>
DoubleGeneric<1,-1>
(0,0) -> (15,0) -> (28,1) -> (36,1)
(1,0) -> (2,0) -> (4,0) -> (16,0) -> (23,0)
(1,2) -> (2,1)
(2,2) -> (3,0)
(4,2) -> (9,0)
(5,0) -> (6,0) -> (8,0) -> (19,0) -> (24,0)
(5,2) -> (6,1)
(6,2) -> (7,0)
(8,2) -> (9,1)
(9,2) -> (14,0)
(10,0) -> (11,0) -> (13,0) -> (20,0) -> (26,0)
(10,2) -> (11,1)
(11,2) -> (12,0)
(13,2) -> (14,1)
(14,2) -> (15,1)
DoubleGeneric<1,0,0,0,-2>
(0,0) -> (46,1) -> (65,1) -> (66,0)
(1,0) -> (3,0) -> (14,0) -> (25,0)
(2,1) -> (3,1)
(3,2) -> (4,1) -> (8,1)
(4,2) -> (7,0)
(5,0) -> (8,0) -> (10,0) -> (11,0)
(5,1) -> (6,0)
(6,2) -> (7,1)
(8,2) -> (9,0)
(10,2) -> (35,0) -> (36,0) -> (47,0) -> (54,0) -> (55,0)
(11,1) -> (12,0)
(13,1) -> (14,1)
(14,2) -> (15,1) -> (19,1)
(15,2) -> (18,0)
(16,0) -> (19,0) -> (21,0) -> (22,0)
(16,1) -> (17,0)
(17,2) -> (18,0)
(20,1) -> (21,0)
(21,2) -> (22,0)
(23,2) -> (25,0)
(24,2) -> (25,1)
(25,2) -> (27,0)
(26,2) -> (27,1)
(27,2) -> (28,0)
(29,0) -> (31,0) -> (34,0)
(30,0) -> (32,0)
(31,2) -> (33,0)
(32,2) -> (33,1)
(33,2) -> (35,0)
(34,2) -> (35,1)
(35,2) -> (36,0)
(17,2) -> (18,1)
(19,2) -> (20,0)
(21,2) -> (38,0) -> (39,0) -> (50,0) -> (57,0) -> (58,0)
(22,1) -> (23,0)
(24,1) -> (25,1)
(25,2) -> (26,1) -> (30,1)
(26,2) -> (29,0)
(27,0) -> (30,0) -> (32,0) -> (33,0)
(27,1) -> (28,0)
(28,2) -> (29,1)
(30,2) -> (31,0)
(32,2) -> (42,0) -> (43,0) -> (51,0) -> (61,0) -> (62,0)
(33,1) -> (34,0)
(35,2) -> (41,0)
(36,1) -> (37,0)
(38,2) -> (41,1)
(39,1) -> (40,0)
(41,2) -> (45,0)
(42,2) -> (45,1)
(43,1) -> (44,0)
(45,2) -> (46,0)
(47,1) -> (48,0)
(48,2) -> (49,0)
(51,1) -> (52,0)
(52,2) -> (53,0)
(54,2) -> (60,0)
(55,1) -> (56,0)
(57,2) -> (60,1)
(58,1) -> (59,0)
(60,2) -> (64,0)
(61,2) -> (64,1)
(62,1) -> (63,0)
(64,2) -> (65,0)
32 changes: 19 additions & 13 deletions examples/fixture/asm/r1cs/generic_builtin_bits.asm
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
@ noname.0.7.0
@ public inputs: 1

v_3 == (v_2) * (v_2 + -1)
0 == (v_3) * (1)
v_5 == (v_4) * (v_4 + -1)
0 == (v_5) * (1)
v_7 == (v_6) * (v_6 + -1)
1 == (v_3) * (1)
v_5 == (v_4) * (-1 * v_2 + v_3)
-1 * v_6 + 1 == (v_5) * (1)
v_7 == (v_6) * (-1 * v_2 + v_3)
0 == (v_7) * (1)
v_2 + 2 * v_4 + 4 * v_6 == (v_1) * (1)
1 == (-1 * v_2 + 1) * (1)
1 == (v_4) * (1)
1 == (-1 * v_6 + 1) * (1)
v_1 == (v_2 + 2 * v_4 + 4 * v_6) * (1)
0 == (v_8) * (1)
1 == (v_9) * (1)
0 == (v_10) * (1)
v_1 == (v_8 + 2 * v_9 + 4 * v_10) * (1)
v_11 == (v_10) * (-1 * v_8 + v_9)
-1 * v_12 + 1 == (v_11) * (1)
v_13 == (v_12) * (-1 * v_8 + v_9)
0 == (v_13) * (1)
1 == (v_15) * (1)
v_17 == (v_16) * (-1 * v_14 + v_15)
-1 * v_18 + 1 == (v_17) * (1)
v_19 == (v_18) * (-1 * v_14 + v_15)
0 == (v_19) * (1)
v_1 == (v_6 + 2 * v_12 + 4 * v_18) * (1)
1 == (-1 * v_6 + 1) * (1)
1 == (v_12) * (1)
1 == (-1 * v_18 + 1) * (1)
v_1 == (v_6 + 2 * v_12 + 4 * v_18) * (1)
2 == (v_1) * (1)
5 changes: 2 additions & 3 deletions examples/generic_builtin_bits.no
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::bits;

// 010 = xx, where xx = 2
fn main(pub xx: Field) {
// var
// calculate on a cell var
let bits = bits::to_bits(3, xx);
assert(!bits[0]);
assert(bits[1]);
Expand All @@ -11,7 +10,7 @@ fn main(pub xx: Field) {
let val = bits::from_bits(bits);
assert_eq(val, xx);

// constant
// calculate on a constant
let cst_bits = bits::to_bits(3, 2);
assert(!cst_bits[0]);
assert(cst_bits[1]);
Expand Down
29 changes: 27 additions & 2 deletions src/cli/cmd_build_and_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ use crate::{
r1cs::{snarkjs::SnarkjsExporter, R1CS},
Backend, BackendField, BackendKind,
},
cli::packages::path_to_package,
cli::packages::{path_to_package, path_to_stdlib},
compiler::{compile, generate_witness, typecheck_next_file, Sources},
inputs::{parse_inputs, JsonInputs},
stdlib::init_stdlib_dep,
type_checker::TypeChecker,
};

use super::packages::{
get_deps_of_package, is_lib, validate_package_and_get_manifest, DependencyGraph, UserRepo,
download_stdlib, get_deps_of_package, is_lib, validate_package_and_get_manifest,
DependencyGraph, UserRepo,
};

const COMPILED_DIR: &str = "compiled";
Expand Down Expand Up @@ -137,6 +139,26 @@ pub fn cmd_check(args: CmdCheck) -> miette::Result<()> {
Ok(())
}

fn add_stdlib<B: Backend>(
sources: &mut Sources,
tast: &mut TypeChecker<B>,
node_id: usize,
) -> miette::Result<usize> {
let mut node_id = node_id;

// check if the release folder exists, otherwise download the latest release
// todo: check the latest version and compare it with the current version, to decide if download is needed
let stdlib_dir = path_to_stdlib();

if !stdlib_dir.exists() {
download_stdlib()?;
}

node_id = init_stdlib_dep(sources, tast, node_id, stdlib_dir.as_ref());

Ok(node_id)
}

fn produce_all_asts<B: Backend>(path: &PathBuf) -> miette::Result<(Sources, TypeChecker<B>)> {
// find manifest
let manifest = validate_package_and_get_manifest(&path, false)?;
Expand All @@ -161,6 +183,9 @@ fn produce_all_asts<B: Backend>(path: &PathBuf) -> miette::Result<(Sources, Type

let mut tast = TypeChecker::new();

// adding stdlib
add_stdlib(&mut sources, &mut tast, node_id)?;

for dep in dep_graph.from_leaves_to_roots() {
let path = path_to_package(&dep);

Expand Down
3 changes: 3 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ pub const NONAME_DIRECTORY: &str = ".noname";

/// The directory under [NONAME_DIRECTORY] containing all package-related files.
pub const PACKAGE_DIRECTORY: &str = "packages";

/// The directory under [NONAME_DIRECTORY] containing all the latest noname release.
pub const RELEASE_DIRECTORY: &str = "release";
52 changes: 51 additions & 1 deletion src/cli/packages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ use camino::Utf8PathBuf as PathBuf;
use miette::{Context, IntoDiagnostic, Result};
use serde::{Deserialize, Serialize};

use crate::stdlib::STDLIB_DIRECTORY;

use super::{
manifest::{read_manifest, Manifest},
NONAME_DIRECTORY, PACKAGE_DIRECTORY,
NONAME_DIRECTORY, PACKAGE_DIRECTORY, RELEASE_DIRECTORY,
};

/// A dependency is a Github `user/repo` pair.
Expand Down Expand Up @@ -241,6 +243,16 @@ pub(crate) fn path_to_package(dep: &UserRepo) -> PathBuf {
package_dir.join(&dep.user).join(&dep.repo)
}

pub(crate) fn path_to_stdlib() -> PathBuf {
let home_dir: PathBuf = dirs::home_dir()
.expect("could not find home directory of current user")
.try_into()
.expect("invalid UTF8 path");
let noname_dir = home_dir.join(NONAME_DIRECTORY);

noname_dir.join(RELEASE_DIRECTORY).join(STDLIB_DIRECTORY)
}

/// download package from github
pub fn download_from_github(dep: &UserRepo) -> Result<()> {
let url = format!(
Expand All @@ -264,6 +276,44 @@ pub fn download_from_github(dep: &UserRepo) -> Result<()> {
Ok(())
}

pub fn download_stdlib() -> Result<()> {
// Hardcoded repository details and target branch
let repo_owner = "zksecurity";
let repo_name = "noname";
Copy link
Contributor

Choose a reason for hiding this comment

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

is that a temporary solution :D

one thing we could do is have a github workflow to remove everything but the lib and push that on a stdlib branch or something. This way we can just git clone this repo with only the latest commit on that branch. wdyt?

Copy link
Contributor

Choose a reason for hiding this comment

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

otherwise it feels a bit wasteful to import all of noname?

ALTHOUGH, it would be cool if, when people click on "go to definition" we could also point to the source code of noname

so it might be an upside to have the whole noname code pulled

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Let's create a release branch for now? so we can decide which version of main branch to be merged into the release branch for auto-download

let target_branch = "main";
let repo_url = format!(
"https://github.com/{owner}/{repo}.git",
owner = repo_owner,
repo = repo_name
);

let home_dir: PathBuf = dirs::home_dir()
.expect("could not find home directory of current user")
.try_into()
.expect("invalid UTF8 path");
let noname_dir = home_dir.join(NONAME_DIRECTORY);
let release_dir = noname_dir.join("release");

// Clone the repository and checkout the specified branch to the temporary directory
let output = process::Command::new("git")
.arg("clone")
.arg("--branch")
.arg(target_branch)
.arg("--single-branch")
.arg(repo_url)
.arg(release_dir)
.output()
.expect("failed to execute git clone command");

if !output.status.success() {
miette::bail!(format!(
"Could not clone branch `{target_branch}` of repository `{repo_owner}/{repo_name}`."
));
}

Ok(())
}

pub fn is_lib(path: &PathBuf) -> bool {
path.join("src").join("lib.no").exists()
}
Expand Down
7 changes: 5 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pub enum ErrorKind {
#[error("invalid array size, expected [_; x] with x in [0,2^32]")]
InvalidArraySize,

#[error("only allow a single generic parameter for the size of an array argument")]
#[error("Invalid expression in symbolic size")]
InvalidSymbolicSize,

#[error("invalid generic parameter, expected single uppercase letter, such as N, M, etc.")]
Expand All @@ -140,7 +140,7 @@ pub enum ErrorKind {
GenericValueExpected(String),

#[error("conflict generic values during binding for `{0}`: `{1}` and `{2}`")]
ConflictGenericValue(String, u32, u32),
ConflictGenericValue(String, String, String),

#[error("unexpected generic parameter: `{0}`")]
UnexpectedGenericParameter(String),
Expand Down Expand Up @@ -361,4 +361,7 @@ pub enum ErrorKind {

#[error("invalid range, the end value can't be smaller than the start value")]
InvalidRange,

#[error("division by zero")]
DivisionByZero,
}
Loading
Loading