Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions benchmarking-suite/frameworks/noir/circuits/anemoi/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "anemoi"
type = "bin"
authors = [""]

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bytes = ["72", "101", "108", "108", "111", "32", "87", "111", "114", "108", "100", "33", "32", "84", "104", "105", "115", "32", "105", "115", "32", "97", "32", "116", "101", "115", "116", "32", "109", "115", "103", "46", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0"]
message_len = "32"
269 changes: 269 additions & 0 deletions benchmarking-suite/frameworks/noir/circuits/anemoi/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
global RATE: u32 = 3;
global CAPACITY: u32 = 1;
global GROUP_GENERATOR: Field = 3;
global NUM_HASH_ROUNDS: u32 = 14;
global NUM_COLUMNS: u32 = 2;
global DELTA: Field = 14592161914559516814830937163504850059130874104865215775126025263096817472389;
global STATE_WIDTH: u32 = RATE + CAPACITY; // 4
pub global MAX_BYTES: u32 = 124; // 4*31
pub global DIGEST_SIZE: u32 = 1; // Field
global ROUND_CONSTANTS_C: [Field; NUM_COLUMNS * NUM_HASH_ROUNDS] = [
35,
10728830232125876048691132003354346755586467280684666879763784946929486129763,
6295152911226189444253866884160054349659895788778004607372136398144290407549,
4170461203170338529741796292530969989683534808908029969258349139824859915904,
21393954857409224592174814995535004102448434148992032619414656579779568689397,
19103935993755851832506530394984072115477780447437172722727915763091375333078,
2634462417634249118966770176700483350170452174029521955965196796017381401956,
9870055416920542367693949347356159207100758622575243892551291274828474900748,
15295217319366023946214435818896821054815840546749644406149416251837787741809,
21367629723253304595356008437306437873020250932614372155612389587750289867011,
4897740601044642812417701466299626155416058382941267461556139867957028325237,
4324119087587322124992127934008257335151923347457111258041741869609415314621,
5767392289724148929423693389240961480732135563465616880868228443921968183406,
6456395601221278483898856214412953805799588482438919310023101480520873192872,
5317720115970311700954487800253539185353124589203406383093606299177363378965,
710253803690889095236417604443336282363034988531359282506781126270380345614,
7178683072420401867285583491757519765705805053793732990705659310878562779654,
13327114523820687328947491054908536262979380425435492467096400458206660578625,
2383742814212199693233039241857741773656918170662619722497679382455110461025,
20164900203441302184815429722225772605937488447067719903152256866067450079451,
21825004911469755557450894072491638633707168470327514863312230079098931792558,
19511933942982909833130072835044780778916343397900214764221687167599966064505,
21450247751664710150210987593785515492243624894603811466130600962437485349126,
13060233182408841069732007751789764082800198352477853683638512640473860490294,
19967544120700448884148022659483814768484183439673469569018785205921257830429,
10084871904716023332756110794661983037429784294614615895805562029971540034206,
18386115521729639027684330339118321986942103783973318486465519864576242574862,
867700948464676294883210265244989471599975912890168408823467958647230813300,
];

global ROUND_CONSTANTS_D: [Field; NUM_COLUMNS * NUM_HASH_ROUNDS] = [
14592161914559516814830937163504850059130874104865215775126025263096817472424,
19360043162052512507098157693689938349509928124442079135790346009357484115856,
14886328771476750059923328797989224350922636562469070718728625674557930694836,
6800688078788018788987346733190881525738862321491292561515374215569680716895,
19638893102775796275277235225427456246362977103230584685008442902017466767651,
11387925254489543159185039151707265794184910140567921269222237884660453925036,
1787913011046289936440351532682066056745691701271258002538193117792994935178,
3062557025699702828743619230168483448468584888709176420024823395935268947674,
6540948924772883830594916229804018068216315941466299076736273903153878004006,
6652412344027284123312577375044376421213313066223223307099783038397560642912,
9293040363042818517653611216357198985940406678571067812961313240862902841192,
2758469864952617473804126210896571700468858381979108090347451041846470344280,
20658070995971503522675594453880534996148127144823809317500067332141426153766,
15386125322835752720726845805883268856008166802689308227555476168071511676936,
16109693438097508500290383924735749637046547901319402337827102095664399270999,
5541278141185205538148402255756288268849045039539551718140812722088596751352,
18656175406244756418120480628945495368630959223459057438730888996407700600910,
18843657873012161523358476718927253400697121333993013396022165943066978913585,
12502826677069997362424575811268729535889132287156664980829561599509861883271,
2434792209826944275336649073210226814265978145156137979695636987808155806818,
16259278398410221045718709682000965909307495157015098081392577671769584472840,
7985258445290494964973976971384849589309256823479994463202570559601799258491,
5279985636464436227957162207029856553960115578931399779648839709840928288577,
12817264954414962013300676637122121768005586932995462140746325081853710152032,
10994211793969826214874362360644675501561401171942888501268420197333659245365,
17038833465191795529304944767910860393995899923074054971644770715360348171429,
19252379911722914953209805612883583535327217956088185615886897738157450269129,
17661259225664347086231179811098267643473987981195055681834419526204845229854,
];

global INV_ALPHA: Field =
17510594297471420177797124596205820070838691520332827474958563349260646796493;

fn mul_by_generator(x: Field) -> Field {
x * GROUP_GENERATOR
}

unconstrained fn pow_unconstrained(base: Field) -> Field {
let exp = INV_ALPHA;
let mut res: Field = 1;
// We explicitly tell the compiler to decompose into 254 bits
let bits = exp.to_le_bits::<254>();

for i in 0..254 {
// Square first (except possibly the very first iteration,
// but squaring 1 is still 1, so this is safe)
res *= res;

// If the bit is 1, multiply by the base
// Note: bits[253 - i] accesses the bits from Most Significant to Least Significant
if bits[253 - i] == 1 {
res *= base;
}
}
res
}

fn exp_by_inv_alpha(x: Field) -> Field {
// Safety: The result is constrained by the assertion below: assert(x == out_4 * out);
let out = unsafe { pow_unconstrained(x) };

// 2. Constrain the result (Secure)
// This is where the 3 gates come in.
let out_2 = out * out;
let out_4 = out_2 * out_2;
assert(x == out_4 * out); // Verifies out^5 == x

out
}

fn apply_ark_layer(state: &mut [Field; STATE_WIDTH], round_counter: u32) {
state[0] += ROUND_CONSTANTS_C[round_counter * NUM_COLUMNS];
state[1] += ROUND_CONSTANTS_C[round_counter * NUM_COLUMNS + 1];
state[2] += ROUND_CONSTANTS_D[round_counter * NUM_COLUMNS];
state[3] += ROUND_CONSTANTS_D[round_counter * NUM_COLUMNS + 1];
}

fn apply_mds_layer(state: &mut [Field; STATE_WIDTH]) {
// apply MDS matrix
state[0] += mul_by_generator(state[1]);
state[1] += mul_by_generator(state[0]);
state[3] += mul_by_generator(state[2]);
state[2] += mul_by_generator(state[3]);
// Swap
let x = state[2];
state[2] = state[3];
state[3] = x;
//PHT layer
state[2] += state[0];
state[3] += state[1];
state[0] += state[2];
state[1] += state[3];
}

fn apply_sbox(state: &mut [Field; STATE_WIDTH]) {
let mut x: [Field; NUM_COLUMNS] = [state[0], state[1]];
let mut y: [Field; NUM_COLUMNS] = [state[2], state[3]];
for i in 0..NUM_COLUMNS {
let y2 = y[i] * y[i];
x[i] = x[i] - mul_by_generator(y2);
}
let mut x_alpha_inv: [Field; NUM_COLUMNS] = [0; NUM_COLUMNS];
for i in 0..NUM_COLUMNS {
x_alpha_inv[i] = exp_by_inv_alpha(x[i]);
}

// y[i] -= x_alpha_inv[i]
for i in 0..NUM_COLUMNS {
y[i] = y[i] - x_alpha_inv[i];
}

// x[i] = x[i] + g * y[i]^2 + DELTA
for i in 0..NUM_COLUMNS {
let y2 = y[i] * y[i];
x[i] = x[i] + GROUP_GENERATOR * y2 + DELTA;
}

for i in 0..NUM_COLUMNS {
state[i] = x[i];
state[i + NUM_COLUMNS] = y[i];
}
}

fn anemoi_permutation(state: &mut [Field; STATE_WIDTH]) {
for round in 0..NUM_HASH_ROUNDS {
apply_ark_layer(state, round);
apply_mds_layer(state);
apply_sbox(state);
}
apply_mds_layer(state);
}

fn bytes31_to_field(bytes: [u8; 31]) -> Field {
let mut acc: Field = 0;
let mut base: Field = 1;

for i in 0..31 {
acc = acc + base * (bytes[i] as Field);
base = base * 256;
}

acc
}

fn get_padded_chunk(bytes: [u8; MAX_BYTES], message_len: u32, chunk_idx: u32) -> [u8; 31] {
let mut out = [0u8; 31];
let start = chunk_idx * 31;

for i in 0..31 {
let idx = start + i;

if idx < message_len {
out[i] = bytes[idx];
} else if idx == message_len {
out[i] = 1; // padding byte
}
}

out
}

pub fn main(bytes: [u8; MAX_BYTES], message_len: u32) -> pub [Field; DIGEST_SIZE] {
// ------------------------------------------------
// 1. Compute number of field elements
// ------------------------------------------------
let mut num_elements = message_len / 31;
if message_len % 31 != 0 {
num_elements += 1;
}

// ------------------------------------------------
// 2. Compute sigma
// ------------------------------------------------
let mut sigma: Field = 0;
if num_elements % RATE == 0 {
sigma = 1;
}

// ------------------------------------------------
// 3. Initialize state
// ------------------------------------------------
let mut state = [0 as Field; STATE_WIDTH];

// ------------------------------------------------
// 4. Absorption phase
// ------------------------------------------------
let mut rate_idx: u32 = 0;
let mut absorbed: u32 = 0;

for chunk_idx in 0..4 {
if chunk_idx < num_elements {
let chunk = get_padded_chunk(bytes, message_len, chunk_idx);
let fe = bytes31_to_field(chunk);

state[rate_idx] = state[rate_idx] + fe;
rate_idx += 1;

if rate_idx == RATE {
anemoi_permutation(&mut state);
rate_idx = 0;
absorbed += RATE;
}
}
}

// ------------------------------------------------
// 5. Add sigma to capacity
// ------------------------------------------------
state[STATE_WIDTH - 1] = state[STATE_WIDTH - 1] + sigma;

// ------------------------------------------------
// 6. Final padding if needed
// ------------------------------------------------
if sigma == 0 {
state[rate_idx] = state[rate_idx] + 1;
anemoi_permutation(&mut state);
}

// ------------------------------------------------
// 7. Squeeze digest
// ------------------------------------------------
let mut digest = [0 as Field; DIGEST_SIZE];
for i in 0..DIGEST_SIZE {
digest[i] = state[i];
}

digest
}
Binary file not shown.

Large diffs are not rendered by default.