Skip to content

Commit fb26918

Browse files
committed
Merge
2 parents 18f64e9 + 1a013be commit fb26918

22 files changed

+338
-4328
lines changed

.github/workflows/build-go.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ jobs:
3131
run: make build_risc_zero_linux
3232
- name: Build Merkle Tree bindings
3333
run: make build_merkle_tree_linux
34-
- name: Build Old Merkle Tree bindings
35-
run: make build_merkle_tree_linux_old
3634
- name: Build operator
3735
run: go build operator/cmd/main.go
3836
- name: Build aggregator

Makefile

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -518,29 +518,15 @@ build_merkle_tree_macos:
518518
@cp operator/merkle_tree/lib/target/$(TARGET_REL_PATH)/libmerkle_tree.dylib operator/merkle_tree/lib/libmerkle_tree.dylib
519519
@cp operator/merkle_tree/lib/target/$(TARGET_REL_PATH)/libmerkle_tree.a operator/merkle_tree/lib/libmerkle_tree.a
520520

521-
build_merkle_tree_macos_old:
522-
@cd operator/merkle_tree_old/lib && cargo build $(RELEASE_FLAG)
523-
@cp operator/merkle_tree_old/lib/target/$(TARGET_REL_PATH)/libmerkle_tree.dylib operator/merkle_tree_old/lib/libmerkle_tree.dylib
524-
@cp operator/merkle_tree_old/lib/target/$(TARGET_REL_PATH)/libmerkle_tree.a operator/merkle_tree_old/lib/libmerkle_tree.a
525-
526521
build_merkle_tree_linux:
527522
@cd operator/merkle_tree/lib && cargo build $(RELEASE_FLAG)
528523
@cp operator/merkle_tree/lib/target/$(TARGET_REL_PATH)/libmerkle_tree.so operator/merkle_tree/lib/libmerkle_tree.so
529524
@cp operator/merkle_tree/lib/target/$(TARGET_REL_PATH)/libmerkle_tree.a operator/merkle_tree/lib/libmerkle_tree.a
530525

531-
build_merkle_tree_linux_old:
532-
@cd operator/merkle_tree_old/lib && cargo build $(RELEASE_FLAG)
533-
@cp operator/merkle_tree_old/lib/target/$(TARGET_REL_PATH)/libmerkle_tree.so operator/merkle_tree_old/lib/libmerkle_tree.so
534-
@cp operator/merkle_tree_old/lib/target/$(TARGET_REL_PATH)/libmerkle_tree.a operator/merkle_tree_old/lib/libmerkle_tree.a
535-
536526
test_merkle_tree_rust_ffi:
537527
@echo "Testing Merkle Tree Rust FFI source code..."
538528
@cd operator/merkle_tree/lib && RUST_MIN_STACK=83886080 cargo t --release
539529

540-
test_merkle_tree_rust_ffi_old:
541-
@echo "Testing Old Merkle Tree Rust FFI source code..."
542-
@cd operator/merkle_tree_old/lib && RUST_MIN_STACK=83886080 cargo t --release
543-
544530
test_merkle_tree_go_bindings_macos: build_merkle_tree_macos
545531
@echo "Testing Merkle Tree Go bindings..."
546532
go test ./operator/merkle_tree/... -v
@@ -553,9 +539,6 @@ test_merkle_tree_old_go_bindings_macos: build_merkle_tree_macos_old
553539
@echo "Testing Old Merkle Tree Go bindings..."
554540
go test ./operator/merkle_tree_old/... -v
555541

556-
test_merkle_tree_go_bindings_linux_old: build_merkle_tree_linux_old
557-
@echo "Testing Merkle Tree Go bindings..."
558-
go test ./operator/merkle_tree_old/... -v
559542

560543
__BUILD_ALL_FFI__:
561544

@@ -568,18 +551,15 @@ build_all_ffi_macos: ## Build all FFIs for macOS
568551
@$(MAKE) build_sp1_macos
569552
@$(MAKE) build_risc_zero_macos
570553
@$(MAKE) build_merkle_tree_macos
571-
@$(MAKE) build_merkle_tree_macos_old
572554
@echo "All macOS FFIs built successfully."
573555

574556
build_all_ffi_linux: ## Build all FFIs for Linux
575557
@echo "Building all FFIs for Linux..."
576558
@$(MAKE) build_sp1_linux
577559
@$(MAKE) build_risc_zero_linux
578560
@$(MAKE) build_merkle_tree_linux
579-
@$(MAKE) build_merkle_tree_linux_old
580561
@echo "All Linux FFIs built successfully."
581562

582-
583563
__EXPLORER__:
584564
run_explorer: explorer_run_db explorer_ecto_setup_db
585565
@cd explorer/ && \
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Getting started!
1+
# Try Aligned
22

33
In this tutorial, you will learn how to send your first SP1 proofs to get verified in Aligned in under 3 minutes.
44

docs/3_guides/0_submitting_proofs.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,14 @@ After depositing funds, you can verify the Service has correctly received them b
8888
```bash
8989
aligned get-user-balance \
9090
--rpc_url https://ethereum-holesky-rpc.publicnode.com \
91+
--network holesky \
9192
--user_addr <user_addr>
9293
```
9394

9495
These commands allow the usage of the following flags:
9596

96-
- `--payment_service_addr` to specify the address of the Batcher Payment Service smart contract.
9797
- `--rpc_url` to specify the rpc url to be used.
98+
- `--network` to specify the chain id to be used. Could be holesky or devnet.
9899
- `--user_addr` the address of the user that funded the Batcher.
99100

100101
## 3. Submit your proof to the batcher
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
# Build your first Application
2+
3+
In this guide you will learn how to build applications on top of Aligned. It provides a few simple steps to help you verify ZK proofs generated within your system.
4+
5+
First we will show you an example of a trivia application, called ZkQuiz. We'll show you the different components and how they interact with each other to be able to submit the proof to aligned and verify that was correctly included in a batch.
6+
7+
## ZkQuiz
8+
9+
ZkQuiz is an application that leverages Aligned's ZK verification infrastructure to run a small trivia. The proof allows any party to check that the quiz was answered right or wrong. If answered correctly, the user receives an NFT.
10+
11+
{% hint style="warning" %}
12+
Received NFTs from ZkQuiz do not have any value. It is just a test application
13+
{% endhint %}
14+
15+
The process is as follows:
16+
17+
1. The user runs ZKQuiz and answers the questions.
18+
2. ZKQuiz generates a ZK Proof of correct answers.
19+
3. The proof is posted on Aligned.
20+
4. Upon verification, ZKQuiz mints an NFT via a Smart Contract.
21+
22+
The NFT is only granted if the user's answers correctly.
23+
Incorrect answers or tampering with the ZKQuiz code will result in proof generation failure or mismatched checksums,
24+
preventing NFT minting.
25+
26+
Next, we will see how to execute ZKQuiz to get your own ZKQuiz NFT!
27+
28+
### Requirements
29+
30+
1. [Rust](https://www.rust-lang.org/tools/install)
31+
2. [Foundry](https://getfoundry.sh)
32+
33+
### Usage
34+
35+
#### 1. Clone the repository
36+
37+
```bash
38+
git clone https://github.com/yetanotherco/aligned_layer.git && cd aligned_layer
39+
```
40+
41+
#### 2. Create a Keystore
42+
43+
You need a keystore to pay for the proof verification, you can use cast to create a local keystore.
44+
If you already have one, you can skip this step.
45+
46+
```bash
47+
cast wallet new-mnemonic
48+
```
49+
50+
Then you can import your created keystore using:
51+
52+
```bash
53+
cast wallet import --interactive <keystore_name>
54+
```
55+
56+
The keystores are saved in `~/.foundry/keystores`. You can find more information about keystores in the [cast documentation](https://book.getfoundry.sh/reference/cast/wallet-commands).
57+
58+
Then you need to get some funds to pay for gas and proof verification.
59+
You can do this by using one of the following faucets:
60+
61+
- [Google Faucet](https://cloud.google.com/application/web3/faucet/ethereum/holesky)
62+
- [Stakely Faucet](https://stakely.io/faucet/ethereum-holesky-testnet-eth)
63+
- [Quicknode Faucet](https://faucet.quicknode.com/ethereum/holesky)
64+
65+
#### 3. Answer Quiz
66+
67+
To answer quiz questions run:
68+
69+
```bash
70+
cd examples/zkquiz
71+
make answer_quiz KEYSTORE_PATH=<path_to_keystore>
72+
```
73+
74+
This will:
75+
76+
1. Ask quiz questions
77+
2. Generate ZK proof
78+
3. Pay & submit proof to aligned for verification
79+
4. Wait for proof to be verified in aligned
80+
5. Claim NFT if proof is verified
81+
82+
## Deep dive
83+
84+
The ZkQuiz source coude is available [here](../../examples/zkquiz).
85+
86+
ZkQuiz has three main components:
87+
- App/script
88+
- Program
89+
- Verifier contract
90+
91+
The user interacts with ZkQuiz App to solve a trivia challenge answering questions. Then, the App generates a Zk Proof with the Program generated using SP1.
92+
93+
{% hint style="info" %}
94+
The ZkQuiz Program is built using SP1 following the [quickstart guide](https://docs.succinct.xyz/getting-started/quickstart.html#project-overview). For your projects, you can user any of the [prooving systems supported by Aligned](../2_architecture/0_supported_verifiers.md).
95+
{% endhint %}
96+
97+
Once the proof is generated, the App sends the proof to Aligned, and once it is verified, the App calls to the ZkQuiz Verifier Contract to check the proof verification and send an NFT to the user is the proof was verified in Aligned.
98+
99+
![ZkQuiz](../images/zkquiz.png)
100+
101+
Now, lets build ZkQuiz from scratch.
102+
103+
### Program
104+
105+
First you need to write the code you want to prove; in this case it looks like this:
106+
107+
```rust
108+
// program/src/main.rs
109+
110+
#![no_main]
111+
112+
use tiny_keccak::{Hasher, Sha3};
113+
sp1_zkvm::entrypoint!(main);
114+
115+
pub fn main() {
116+
let answers = sp1_zkvm::io::read::<String>();
117+
let mut sha3 = Sha3::v256();
118+
let mut output = [0u8; 32];
119+
120+
sha3.update(answers.as_bytes());
121+
122+
sha3.finalize(&mut output);
123+
124+
if output
125+
!= [
126+
232, 202, 155, 157, 82, 242, 126, 73, 75, 22, 197, 34, 41, 170, 163, 190, 22, 29, 192,
127+
5, 99, 134, 186, 25, 77, 128, 188, 154, 238, 70, 245, 229,
128+
]
129+
{
130+
panic!("Answers do not match");
131+
}
132+
}
133+
```
134+
135+
The program takes the user answers as inputs and checks that the hash of the inputs matches with the expected output. This is the program that will be compiled generati ng a binary file that will be ran by the zkVm and used later in the application side. In our case this file is already generated and is located on `/quiz/program/elf/riscv32im-succinct-zkvm-elf`.
136+
137+
### Verifier Contract
138+
139+
To check if a proof was verified in Aligned, you can create your own smart contract in order to make a call to the `AlignedServiceManager` contract.
140+
141+
ZkQuiz uses a Smart Contract to check if aligned verified the proof and gives an NFT to the user.
142+
143+
{% hint style="info" %}
144+
It is not mandatory to create an Smart Contract. You can make off-chain apps that interact with the Aligned contract directly.
145+
{% endhint %}
146+
147+
**Program Identifier Validation**
148+
149+
The contract first checks that the commitment of the program matches with the one that we expect.
150+
151+
In our zkquiz example, we get the following elf_commitment:
152+
153+
```solidity
154+
// contracts/src/VerifierContract.sol
155+
156+
bytes32 public elfCommitment = 0x3f99615fdf3b67a01e41b38eee75a32c778ee2fa631bd74e01c89afc2f70f5de;
157+
158+
if (elfCommitment != provingSystemAuxDataCommitment) {
159+
revert InvalidElf(provingSystemAuxDataCommitment);
160+
}
161+
```
162+
163+
You can generate the expected commitment without actually generating and submitting a proof using the Aligned CLI tool running:
164+
165+
```bash
166+
aligned get-vk-commitment --verification_key_file <path_to_input_file> --proving_system <proving_system_id>
167+
```
168+
where the `path_to_input_file` is the path to the `elf` file generated with the program compilation and the `proving_system_id` the name of the proving system used for compilation, in this case `SP1`.
169+
170+
Then, the contract validates if the provided commitment of the program identifier matches the expected one.
171+
172+
```solidity
173+
// contracts/src/VerifierContract.sol
174+
if (elfCommitment != provingSystemAuxDataCommitment) {
175+
revert InvalidElf(provingSystemAuxDataCommitment);
176+
}
177+
```
178+
179+
The contract makes a call to the `AlignedServiceManager` contract to check if the proof was verified in Aligned.
180+
181+
```solidity
182+
// contracts/src/VerifierContract.sol
183+
(
184+
bool callWasSuccessfull,
185+
bytes memory proofIsIncluded
186+
) = alignedServiceManager.staticcall(
187+
abi.encodeWithSignature(
188+
"verifyBatchInclusion(bytes32,bytes32,bytes32,bytes20,bytes32,bytes,uint256,address)",
189+
proofCommitment,
190+
pubInputCommitment,
191+
provingSystemAuxDataCommitment,
192+
proofGeneratorAddr,
193+
batchMerkleRoot,
194+
merkleProof,
195+
verificationDataBatchIndex,
196+
paymentServiceAddr
197+
)
198+
);
199+
200+
require(callWasSuccessfull, "static_call failed");
201+
202+
bool proofIsIncludedBool = abi.decode(proofIsIncluded, (bool));
203+
204+
require(proofIsIncludedBool, "proof not included in batch");
205+
```
206+
207+
Finally, if the proof was verified, the contract sends a NFT to the user
208+
209+
```solidity
210+
// contracts/src/VerifierContract.sol
211+
212+
_mint(msg.sender, tokenId);
213+
_setTokenURI(
214+
tokenId,
215+
"ipfs://QmUKviny9x2oQUegyJFFBAUU2q5rvu5CsPzrUaBSDukpHQ"
216+
);
217+
```
218+
219+
### App
220+
221+
The first part of the app takes the answers of the user via CLI.
222+
Once the user answer the questions, we prepare them and initiate the prover, as follows:
223+
224+
```rust
225+
// script/src/main.rs
226+
227+
// Include the bytes of the compiled program.
228+
const ELF: &[u8] = include_bytes!("../../program/elf/riscv32im-succinct-zkvm-elf");
229+
230+
// Generate proof.
231+
let mut stdin = SP1Stdin::new();
232+
233+
stdin.write(&user_awnsers);
234+
235+
println!("Generating Proof ");
236+
237+
let client = ProverClient::new();
238+
let (pk, vk) = client.setup(ELF);
239+
240+
let Ok(proof) = client.prove(&pk, stdin).run() else {
241+
println!("Incorrect answers!");
242+
return;
243+
};
244+
245+
println!("Proof generated successfully. Verifying proof...");
246+
client.verify(&proof, &vk).expect("verification failed");
247+
println!("Proof verified successfully.");
248+
```
249+
250+
Now we can send the generated proof to Aligned using the SDK.
251+
252+
```rust
253+
// script/src/main.rs
254+
255+
// Serialize the proof to later save in a file.
256+
let proof = bincode::serialize(&proof).expect("Failed to serialize proof");
257+
258+
// Preparing the data needed for verification in Aligned
259+
let verification_data = VerificationData {
260+
proving_system: ProvingSystemId::SP1,
261+
proof,
262+
proof_generator_addr: wallet.address(),
263+
vm_program_code: Some(ELF.to_vec()),
264+
verification_key: None,
265+
pub_input: None,
266+
};
267+
268+
let max_fee = estimate_fee(&rpc_url, PriceEstimate::Default)
269+
.await
270+
.expect("failed to fetch gas price from the blockchain");
271+
272+
let max_fee_string = ethers::utils::format_units(max_fee, 18).unwrap();
273+
274+
let nonce = get_next_nonce(&rpc_url, wallet.address(), NETWORK)
275+
.await
276+
.expect("Failed to get next nonce");
277+
278+
// Submit to Aligned.
279+
let aligned_verification_data = submit_and_wait_verification(
280+
BATCHER_URL,
281+
&rpc_url,
282+
NETWORK,
283+
&verification_data,
284+
max_fee,
285+
wallet.clone(),
286+
nonce,
287+
)
288+
.await
289+
.unwrap();
290+
```
291+
292+
Finally, if the proof was sent to Aligned correctly, we can interact with our verifier Smart Contract to verify that the proof was correctly posted in aligned and claim the NFT.
293+
294+
```rust
295+
// script/src/main.rs
296+
297+
// Sends a transaction to the verifier contract with the
298+
// verification data provided by aligned
299+
claim_nft_with_verified_proof(
300+
&aligned_verification_data,
301+
signer,
302+
&args.verifier_contract_address,
303+
)
304+
.await
305+
.expect("Claiming of NFT failed ...");
306+
```
307+
308+
You can find the full code of the proof submission and verification in the [ZKQuiz App](../../examples/zkquiz/quiz/script/src/main.rs).

0 commit comments

Comments
 (0)