Skip to content

Commit 36a5314

Browse files
committed
[frontend] Add Blake2s circuit
1 parent d9a08ae commit 36a5314

File tree

6 files changed

+954
-1
lines changed

6 files changed

+954
-1
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ jobs:
141141
strategy:
142142
fail-fast: false
143143
matrix:
144-
example: [zklogin, sha256, keccak]
144+
example: [zklogin, sha256, keccak, blake2s]
145145
steps:
146146
- name: Checkout Repository
147147
uses: actions/checkout@v4

crates/examples/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ tracing-profile.workspace = true
1919

2020
[dev-dependencies]
2121
base64.workspace = true
22+
blake2.workspace = true
2223
jwt-simple.workspace = true
2324
rand.workspace = true
2425
sha2.workspace = true
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use anyhow::{Result, ensure};
2+
use binius_examples::{Cli, ExampleCircuit};
3+
use binius_frontend::{
4+
circuits::blake2s::Blake2s,
5+
compiler::{CircuitBuilder, circuit::WitnessFiller},
6+
};
7+
use blake2::{Blake2s256, Digest};
8+
use clap::Args;
9+
use rand::prelude::*;
10+
11+
/// Blake2s circuit example demonstrating the Blake2s hash function implementation
12+
struct Blake2sExample {
13+
blake2s_gadget: Blake2s,
14+
}
15+
16+
/// Circuit parameters that affect structure (compile-time configuration)
17+
#[derive(Args, Debug)]
18+
struct Params {
19+
/// Maximum message length in bytes that the circuit can handle.
20+
#[arg(long, default_value_t = 128)]
21+
max_message_len: usize,
22+
}
23+
24+
/// Instance data for witness population (runtime values)
25+
#[derive(Args, Debug)]
26+
#[group(multiple = false)]
27+
struct Instance {
28+
/// Length of the randomly generated message, in bytes (defaults to half of --max-message-len).
29+
#[arg(long)]
30+
message_len: Option<usize>,
31+
32+
/// UTF-8 string to hash (if not provided, random bytes are generated)
33+
#[arg(long)]
34+
message_string: Option<String>,
35+
}
36+
37+
impl ExampleCircuit for Blake2sExample {
38+
type Params = Params;
39+
type Instance = Instance;
40+
41+
fn build(params: Params, builder: &mut CircuitBuilder) -> Result<Self> {
42+
// Create the Blake2s gadget with witness wires
43+
let blake2s_gadget = Blake2s::new_witness(builder, params.max_message_len);
44+
45+
Ok(Self { blake2s_gadget })
46+
}
47+
48+
fn populate_witness(&self, instance: Instance, w: &mut WitnessFiller) -> Result<()> {
49+
// Determine the message bytes to hash
50+
let message_bytes = if let Some(message_string) = instance.message_string {
51+
// Use provided UTF-8 string
52+
message_string.as_bytes().to_vec()
53+
} else {
54+
// Generate random bytes
55+
let mut rng = StdRng::seed_from_u64(0);
56+
let len = instance
57+
.message_len
58+
.unwrap_or(self.blake2s_gadget.max_message_len / 2);
59+
60+
let mut message_bytes = vec![0u8; len];
61+
rng.fill_bytes(&mut message_bytes);
62+
message_bytes
63+
};
64+
65+
// Validate message length
66+
ensure!(
67+
message_bytes.len() <= self.blake2s_gadget.max_message_len,
68+
"Message length ({}) exceeds maximum ({})",
69+
message_bytes.len(),
70+
self.blake2s_gadget.max_message_len
71+
);
72+
73+
// Compute the expected Blake2s digest using the reference implementation
74+
let mut hasher = Blake2s256::new();
75+
hasher.update(&message_bytes);
76+
let digest = hasher.finalize();
77+
let digest_array: [u8; 32] = digest.into();
78+
79+
// Populate the witness values
80+
self.blake2s_gadget.populate_message(w, &message_bytes);
81+
self.blake2s_gadget.populate_digest(w, &digest_array);
82+
83+
Ok(())
84+
}
85+
}
86+
87+
fn main() -> Result<()> {
88+
let _tracing_guard = tracing_profile::init_tracing()?;
89+
90+
// Create and run the CLI
91+
Cli::<Blake2sExample>::new("blake2s")
92+
.about("Blake2s hash function circuit example")
93+
.long_about(
94+
"Blake2s cryptographic hash function circuit implementation.\n\
95+
\n\
96+
This example demonstrates the Blake2s hash function which produces \
97+
32-byte digests. Blake2s is optimized for 32-bit platforms and is \
98+
faster than Blake2b on such architectures.\n\
99+
\n\
100+
The circuit supports variable-length messages up to the specified \
101+
maximum length. It implements the full Blake2s algorithm as \
102+
specified in RFC 7693, including 10 rounds of the compression \
103+
function.\n\
104+
\n\
105+
Examples:\n\
106+
\n\
107+
Hash a string:\n\
108+
cargo run --release --example blake2s -- --message-string \"Hello, World!\"\n\
109+
\n\
110+
Generate and hash random data (64 bytes):\n\
111+
cargo run --release --example blake2s -- --message-len 64\n\
112+
\n\
113+
Test with maximum message length:\n\
114+
cargo run --release --example blake2s -- --max-message-len 256 --message-len 256",
115+
)
116+
.run()
117+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
blake2s circuit
2+
--
3+
Number of gates: 2929
4+
Number of evaluation instructions: 3209
5+
Number of AND constraints: 4027
6+
Number of MUL constraints: 0
7+
Length of value vec: 8192
8+
Constants: 141
9+
Inout: 0
10+
Witness: 165
11+
Internal: 3991

0 commit comments

Comments
 (0)