We are thrilled to announce that noname, zkSecurity’s programming language to write ZK circuits, now supports R1CS! This update allows developers to write ZK circuits in a rust-and-golang-inspired language and deploy them to Ethereum using SnarkJS. This offers an alternative to the widely-used Circom language for zk-SNARK proofs on Ethereum. In this post, you’ll see the first noname circuit deployed on Ethereum, and we’ll show you how to deploy one yourself.

The zero-knowledge field is evolving rapidly, with new proof systems and frameworks frequently emerging. Developers face a major challenge: fragmentation. Each proof system has its own language and quirks, often targeting specific projects and unavailable on other platforms. For example, Noir is for Aztec Network, Leo is for Aleo, Cairo is for Starknet, and O1js is for Mina.

What if there was a way to bridge this gap? A language that could unify the zk ecosystem, allowing developers to write circuits that work across different backends.

This is what we’re doing! while noname was first created to compile programs to work with Mina’s kimchi proof system, we are now updating it to work with Ethereum’s SnarkJS.

It receives two arguments: the Sudoku problem as a public input, and the solution as a secret.

At a high level, this sudoku circuit checks:

the solution grid matches with the sudoku problem (encoded in the public inputs)

verify the solution indeed follows the sudoku rules

In Noname, grid: Sudoku automatically interprets inputs as the Sudoku type:

structSudoku {
inner: [Field; 81],
}

Here is how it checks if the solution matches with the grid of a solution problem.

// return the value in a given cell
fnSudoku.cell(self, const row: Field, const col: Field) -> Field {
return self.inner[(row *9) + col];
}
// verifies that self matches the grid in places where the grid has numbers
fnSudoku.matches(self, grid: Sudoku) {
// for each cell
for row in0..9 {
for col in0..9 {
// either the solution matches the grid
// or the grid is zero
let matches = self.cell(row, col) == grid.cell(row, col);
let is_empty = grid.cell(row, col) == empty;
assert(matches || is_empty);
}
}
}

Next, the program verifies the solution according to sudoku roles:

fnSudoku.verify(self) {
self.verify_rows();
self.verify_cols();
self.verify_diagonals();
}
fnSudoku.verify_rows(self) {
for row in0..9 {
for num in1..10 {
letmut found =false;
for col in0..9 {
let found_one = self.cell(row, col) == num;
found = found || found_one;
}
assert(found);
}
}
}
fnSudoku.verify_cols(self) {
for col in0..9 {
for num in1..10 {
letmut found =false;
for row in0..9 {
let found_one = self.cell(row, col) == num;
found = found || found_one;
}
assert(found);
}
}
}
fnSudoku.verify_diagonals(self) {
for num in1..10 {
// first diagonal
letmut found1 =false;
for row1 in0..9 {
let temp1 = self.cell(row1, row1) == num;
found1 = found1 || temp1;
}
assert(found1);
// second diagonal
letmut found2 =false;
for row2 in0..9 {
let temp2 = self.cell(8- row2, row2) == num;
found2 = found2 || temp2;
}
assert(found2);
}
}

As it is shown above, the typing support behind the language makes circuit code straightforward, akin to writing in conventional languages.

Plugging into Snarkjs

Now that we have the sudoku code, we can use the noname CLI to generate and run circuits that are compatible with Snarkjs.

There is a script to quickly test the compatibility of these outputs with the SnarkJS. The script automatically generates the proof and verifies it off-chain via SnarkJS.

Intuitively, the calldata contains the contract call arguments to represent a sudoku problem (the public inputs in the circuit) and a proof for the corresponding solution (without revealing it).

As the screenshot shown (from remix), if the proof(_pA, _pB, _pC) and the sudoku problem matches (_pubSignals), then the contract call to verifyProof should return true.

What’s next?

noname is a work-in-progress language, and many features are missing! We’re looking for help and contributions. If you’re interested, check the issues.

To learn more about Noname, please check out the repo, or the following blog posts and videos: