-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/main' into merkle_tree_tests
- Loading branch information
Showing
12 changed files
with
1,336 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
[package] | ||
name = "liminal-halo2-relations" | ||
version = "0.0.0" | ||
edition = "2021" | ||
authors = ["Cardinal"] | ||
documentation = "https://docs.rs/?" | ||
homepage = "https://alephzero.org" | ||
license = "Apache-2.0" | ||
categories = ["cryptography"] | ||
keywords = ["cryptography", "snark", "zero-knowledge", "liminal", "shielder"] | ||
repository = "https://github.com/Cardinal-Cryptography/zk-apps" | ||
description = "A collection of halo2-based relations for use in liminal." | ||
|
||
[dependencies] | ||
rand = "=0.8" | ||
serde = { version = "=1.0", default-features = false, features = ["derive"] } | ||
serde_json = "=1.0" | ||
|
||
halo2-base = { package = "halo2-base", git = "https://github.com/Cardinal-Cryptography/halo2-lib", branch = "aleph" } | ||
|
||
|
||
#[dev-dependencies] | ||
# Fork with halo2curves = 0.6 to match the version of halo2-base | ||
poseidon = { git = "https://github.com/zemse/pse-poseidon" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#Notes and Accounts | ||
|
||
#Relations | ||
|
||
#Tests | ||
|
||
``` | ||
cargo test | ||
``` | ||
|
||
#Benchmarks |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[toolchain] | ||
channel = "nightly-2023-12-21" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
use halo2_base::{gates::GateChip, utils::BigPrimeField, AssignedValue, Context}; | ||
|
||
use crate::{ | ||
operation::{CircuitOperation, Operation}, | ||
CloneToVec, | ||
}; | ||
|
||
pub trait Account<F: BigPrimeField>: CloneToVec<F> { | ||
type CircuitAccount: CircuitAccount<F>; | ||
type Op: Operation<F>; | ||
|
||
fn update(&self, op: &Self::Op) -> Self; | ||
|
||
fn load(&self, ctx: &mut Context<F>) -> Self::CircuitAccount; | ||
} | ||
|
||
pub trait CircuitAccount<F: BigPrimeField>: CloneToVec<AssignedValue<F>> { | ||
type Op: CircuitOperation<F>; | ||
|
||
fn update(&self, op: Self::Op, ctx: &mut Context<F>, gate: &GateChip<F>) -> Self; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
pub mod account; | ||
pub mod merkle_proof; | ||
pub mod note; | ||
pub mod operation; | ||
pub mod relations; | ||
|
||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | ||
pub enum Token { | ||
AZERO, | ||
USDT, | ||
} | ||
|
||
pub trait CloneToVec<T> { | ||
fn clone_to_vec(&self) -> Vec<T>; | ||
} | ||
|
||
pub mod poseidon_consts { | ||
/// Has to be greater than 1 and equal to RATE + 1, due to the outer Poseidon implementation. | ||
pub const T_WIDTH: usize = RATE + 1; | ||
|
||
pub const RATE: usize = 4; | ||
|
||
pub const R_F: usize = 8; | ||
|
||
pub const R_P: usize = 56; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
use halo2_base::{ | ||
gates::{GateChip, GateInstructions}, | ||
poseidon::hasher::PoseidonHasher, | ||
utils::BigPrimeField, | ||
AssignedValue, Context, | ||
}; | ||
|
||
use crate::poseidon_consts::{RATE, T_WIDTH}; | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct MerkleProof<F: BigPrimeField, const TREE_HEIGHT: usize> { | ||
pub path_shape: [bool; TREE_HEIGHT], | ||
pub path: [F; TREE_HEIGHT], | ||
} | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct CircuitMerkleProof<F: BigPrimeField, const TREE_HEIGHT: usize> { | ||
pub path_shape: [AssignedValue<F>; TREE_HEIGHT], | ||
pub path: [AssignedValue<F>; TREE_HEIGHT], | ||
} | ||
|
||
impl<F: BigPrimeField, const TREE_HEIGHT: usize> MerkleProof<F, TREE_HEIGHT> { | ||
pub fn new(path_shape: [bool; TREE_HEIGHT], path: [F; TREE_HEIGHT]) -> Self { | ||
Self { path_shape, path } | ||
} | ||
|
||
pub fn load(&self, ctx: &mut Context<F>) -> CircuitMerkleProof<F, TREE_HEIGHT> { | ||
let path_shape = self | ||
.path_shape | ||
.map(|x| ctx.load_witness(F::from_u128(x as u128))); | ||
let path = self.path.map(|x| ctx.load_witness(x)); | ||
|
||
CircuitMerkleProof { path_shape, path } | ||
} | ||
} | ||
|
||
impl<F: BigPrimeField, const TREE_HEIGHT: usize> CircuitMerkleProof<F, TREE_HEIGHT> { | ||
pub fn verify( | ||
&self, | ||
ctx: &mut Context<F>, | ||
gate: &GateChip<F>, | ||
poseidon: &mut PoseidonHasher<F, T_WIDTH, RATE>, | ||
root: AssignedValue<F>, | ||
leaf: AssignedValue<F>, | ||
) { | ||
let mut current_node = leaf; | ||
|
||
// TREE_HIGHT is definied in a way that path[TREE_HIGHT] would be the root | ||
for i in 0..TREE_HEIGHT { | ||
let sibling = self.path[i]; | ||
let shape = self.path_shape[i]; | ||
|
||
let selector = gate.is_zero(ctx, shape); | ||
let left = gate.select(ctx, sibling, current_node, selector); | ||
let right = gate.select(ctx, current_node, sibling, selector); | ||
current_node = poseidon.hash_fix_len_array(ctx, gate, &[left, right]); | ||
} | ||
|
||
let eq = gate.is_equal(ctx, current_node, root); | ||
gate.assert_is_const(ctx, &eq, &F::ONE); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use halo2_base::{utils::ScalarField, AssignedValue, Context}; | ||
|
||
use crate::CloneToVec; | ||
|
||
#[derive(Clone, Copy, Debug)] | ||
pub struct Note<F: ScalarField> { | ||
pub zk_id: F, | ||
pub trapdoor: F, | ||
pub nullifier: F, | ||
pub account_hash: F, | ||
} | ||
|
||
impl<F: ScalarField> Note<F> { | ||
pub fn new(note_id: F, trapdoor: F, nullifier: F, account_hash: F) -> Self { | ||
Self { | ||
zk_id: note_id, | ||
trapdoor, | ||
nullifier, | ||
account_hash, | ||
} | ||
} | ||
|
||
pub fn load(&self, ctx: &mut Context<F>) -> CircuitNote<F> { | ||
CircuitNote { | ||
zk_id: ctx.load_witness(self.zk_id), | ||
trapdoor: ctx.load_witness(self.trapdoor), | ||
nullifier: ctx.load_witness(self.nullifier), | ||
account_hash: ctx.load_witness(self.account_hash), | ||
} | ||
} | ||
} | ||
|
||
impl<F: ScalarField> CloneToVec<F> for Note<F> { | ||
fn clone_to_vec(&self) -> Vec<F> { | ||
vec![self.zk_id, self.trapdoor, self.nullifier, self.account_hash] | ||
} | ||
} | ||
|
||
#[derive(Clone, Copy, Debug)] | ||
pub struct CircuitNote<F: ScalarField> { | ||
pub zk_id: AssignedValue<F>, | ||
pub trapdoor: AssignedValue<F>, | ||
pub nullifier: AssignedValue<F>, | ||
pub account_hash: AssignedValue<F>, | ||
} | ||
|
||
impl<F: ScalarField> CloneToVec<AssignedValue<F>> for CircuitNote<F> { | ||
fn clone_to_vec(&self) -> Vec<AssignedValue<F>> { | ||
vec![self.zk_id, self.trapdoor, self.nullifier, self.account_hash] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use halo2_base::{utils::BigPrimeField, AssignedValue, Context}; | ||
|
||
pub trait Operation<F> | ||
where | ||
Self: Sized, | ||
F: BigPrimeField, | ||
{ | ||
type OpPriv: Into<Vec<F>>; | ||
type OpPub: Into<Vec<F>>; | ||
|
||
fn combine(op_priv: Self::OpPriv, op_pub: Self::OpPub) -> Option<Self>; | ||
} | ||
|
||
pub trait CircuitOperation<F> | ||
where | ||
Self: Sized, | ||
F: BigPrimeField, | ||
{ | ||
type OpPriv: From<Vec<AssignedValue<F>>>; | ||
type OpPub: From<Vec<AssignedValue<F>>> + Into<Vec<AssignedValue<F>>> + Clone; | ||
|
||
fn combine(op_priv: Self::OpPriv, op_pub: Self::OpPub) -> Option<Self>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod update_account; | ||
pub mod update_note; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
use halo2_base::{ | ||
gates::{GateChip, GateInstructions}, | ||
poseidon::hasher::{spec::OptimizedPoseidonSpec, PoseidonHasher}, | ||
utils::BigPrimeField, | ||
AssignedValue, | ||
}; | ||
#[allow(unused_imports)] | ||
use halo2_base::{ | ||
Context, | ||
QuantumCell::{Constant, Existing, Witness}, | ||
}; | ||
|
||
use crate::{ | ||
account::CircuitAccount, | ||
poseidon_consts::{RATE, R_F, R_P, T_WIDTH}, | ||
}; | ||
|
||
pub struct UpdateAccountInput<F, A> | ||
where | ||
F: BigPrimeField, | ||
A: CircuitAccount<F>, | ||
{ | ||
//public inputs | ||
pub old_account_hash: AssignedValue<F>, | ||
pub new_account_hash: AssignedValue<F>, | ||
pub operation: A::Op, | ||
|
||
//witnesses | ||
pub old_account: A, | ||
} | ||
|
||
impl<F, A> UpdateAccountInput<F, A> | ||
where | ||
F: BigPrimeField, | ||
A: CircuitAccount<F>, | ||
{ | ||
pub fn new( | ||
old_account_hash: AssignedValue<F>, | ||
new_account_hash: AssignedValue<F>, | ||
operation: A::Op, | ||
old_account: A, | ||
) -> Self { | ||
Self { | ||
old_account_hash, | ||
new_account_hash, | ||
operation, | ||
old_account, | ||
} | ||
} | ||
} | ||
|
||
pub fn verify_account_circuit<F, A>( | ||
ctx: &mut Context<F>, | ||
gate: &GateChip<F>, | ||
poseidon: &mut PoseidonHasher<F, T_WIDTH, RATE>, | ||
account: &A, | ||
account_hash: AssignedValue<F>, | ||
) where | ||
F: BigPrimeField, | ||
A: CircuitAccount<F>, | ||
{ | ||
let inner_account_hash = poseidon.hash_fix_len_array(ctx, gate, &account.clone_to_vec()); | ||
let eq = gate.is_equal(ctx, account_hash, inner_account_hash); | ||
gate.assert_is_const(ctx, &eq, &F::ONE); | ||
} | ||
|
||
#[allow(dead_code)] | ||
pub fn update_account_circuit<F, A>(ctx: &mut Context<F>, input: UpdateAccountInput<F, A>) | ||
where | ||
F: BigPrimeField, | ||
A: CircuitAccount<F>, | ||
{ | ||
let gate = GateChip::<F>::default(); | ||
let mut poseidon = | ||
PoseidonHasher::<F, T_WIDTH, RATE>::new(OptimizedPoseidonSpec::new::<R_F, R_P, 0>()); | ||
poseidon.initialize_consts(ctx, &gate); | ||
|
||
let old_account = input.old_account; | ||
verify_account_circuit( | ||
ctx, | ||
&gate, | ||
&mut poseidon, | ||
&old_account, | ||
input.old_account_hash, | ||
); | ||
|
||
let new_account = old_account.update(input.operation, ctx, &gate); | ||
verify_account_circuit( | ||
ctx, | ||
&gate, | ||
&mut poseidon, | ||
&new_account, | ||
input.new_account_hash, | ||
); | ||
} |
Oops, something went wrong.