Skip to content

Commit

Permalink
Minor changes. Addition of BN254-specific permutation and sponge func…
Browse files Browse the repository at this point in the history
…tions.
  • Loading branch information
ax0 committed Feb 8, 2023
1 parent 64c33f2 commit 6992c54
Show file tree
Hide file tree
Showing 6 changed files with 326 additions and 398 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
x = [1,2,3,4,5,6,7]
#return = "0x080ae1669d62f0197190573d4a325bfb8d8fc201ce3127cbac0c47a7ac81ac48"
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use dep::std::hash::poseidon;

fn main(x: [Field; 7]) -> pub Field
fn main(x: [Field; 7])
{
let perm = poseidon::bn254::sponge(x);

perm
let result = poseidon::bn254::sponge(x);
constrain result == 0x080ae1669d62f0197190573d4a325bfb8d8fc201ce3127cbac0c47a7ac81ac48;
}
87 changes: 53 additions & 34 deletions noir_stdlib/src/hash/poseidon.nr
Original file line number Diff line number Diff line change
@@ -1,85 +1,104 @@
mod bn254; // Instantiations of Poseidon for prime field of the same order as BN254

use crate::array;
use crate::pow_32;
mod bn254; // Instantiations of Poseidon for prime field of the same order as BN254
use crate::field::modulus_num_bits;

// General Poseidon permutation on elements of type Field
fn permute<N,O,P>(rf: u8, // Number of full rounds; should be even
rp: u8, // Number of partial rounds
alpha: Field, // S-box power, depending on the underlying field
ark: [Field; O], // Additive round keys
mds_matrix: [Field; P], // MDS Matrix in row-major order
state: [Field; N] // State as an array of length t = c + r
) -> [Field; N]
struct PoseidonConfig<M,N>
{
let t = array::len(state);
t: comptime Field, // Width, i.e. state size
rf: comptime u8, // Number of full rounds; should be even
rp: comptime u8, // Number of partial rounds
alpha: comptime Field, // S-box power; depends on the underlying field
ark: [Field; M], // Additive round keys
mds: [Field; N] // MDS Matrix in row-major order
}

fn config<M,N>(t: comptime Field, rf: comptime u8, rp: comptime u8, alpha: comptime Field,
ark: [Field; M], mds: [Field; N]) -> PoseidonConfig<M,N>
{
// Input checks
constrain t as u8 * (rf + rp) == array::len(ark) as u8;
constrain t * t == array::len(mds_matrix);
constrain t * t == array::len(mds);
constrain alpha > 0;

let mut count = 0;
PoseidonConfig {t, rf, rp, alpha, ark, mds}
}

let mut out_perm = state;
// General Poseidon permutation on elements of type Field
fn permute<M,N,O>(pos_conf: PoseidonConfig<M, N>, mut state: [Field; O])
-> [Field; O]
{
let PoseidonConfig {t, rf, rp, alpha, ark, mds} = pos_conf;

constrain t == array::len(state);

let mut count = 0;

for r in 0..(array::len(ark)/array::len(state)) // i.e. r in 0..rf + rp
{
for i in 0..array::len(state)
{
out_perm[i] = out_perm[i] + ark[count + i];
state[i] = state[i] + ark[count + i];
} // Shift by round constants

out_perm[0] = pow_32(out_perm[0], alpha);
state[0] = pow_32(state[0], alpha);

if (r as u8 < rf/2) | (r as u8 >= rf/2 + rp) // Check whether we are in a full round
{
for i in 1..array::len(state)
{
out_perm[i] = pow_32(out_perm[i], alpha);
state[i] = pow_32(state[i], alpha);
}
}

out_perm = apply_matrix(mds_matrix, out_perm); // Apply MDS matrix
state = apply_matrix(mds, state); // Apply MDS matrix
count = count + t;
}

out_perm
state
}

// Absorption. Fully absorbs input message.
fn absorb<N,O,P,Q>(rf: u8,
rp: u8,
alpha: Field,
ark: [Field; O],
mds_matrix: [Field; P],
state: [Field; N], // Initial state; usually [0; N]
rate: Field, // Rate
fn absorb<M,N,O,P>(pos_conf: PoseidonConfig<M, N>,
mut state: [Field; O], // Initial state; usually [0; N]
rate: comptime Field, // Rate
capacity: comptime Field, // Capacity; usually 1
msg: [Field; Q] // Arbitrary length message
) -> [Field; N]
msg: [Field; P] // Arbitrary length message
) -> [Field; O]
{
let mut block = state;

constrain pos_conf.t == rate + capacity;

let mut i = 0;

for k in 0..array::len(msg)
{
// Populate block
block[capacity + i] += msg[k];
// Add current block to state
state[capacity + i] += msg[k];
i = i+1;
if i == rate // Enough to absorb
{
block = permute(rf, rp, alpha, ark, mds_matrix, block);
state = permute(pos_conf, state);
i = 0;
}
};

if i > 0 // If we have one more block to permute
{
block = permute(rf, rp, alpha, ark, mds_matrix, block);
state = permute(pos_conf, state);
}

block
state
}


// Check security of sponge instantiation
fn check_security(rate: Field, width: Field, security: Field) -> bool
{
let n = modulus_num_bits();

((n-1)*(width-rate)/2) as u8 > security as u8
}

// A*x where A is an n x n matrix in row-major order and x an n-vector
Expand Down
102 changes: 101 additions & 1 deletion noir_stdlib/src/hash/poseidon/bn254.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,108 @@
mod perm;
mod consts;

use crate::hash::poseidon::PoseidonConfig;
use crate::array;
use crate::pow_32;
use crate::hash::poseidon::apply_matrix;

// Optimised permutation for this particular field
fn permute<M,N,O>(pos_conf: PoseidonConfig<M, N>, mut state: [Field; O])
-> [Field; O]
{
let PoseidonConfig {t, rf: config_rf, rp: config_rp, alpha, ark, mds} = pos_conf;
let rf = 8;
let rp = [56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68][array::len(state) - 2];

constrain t == array::len(state);
constrain rf == config_rf as Field;
constrain rp == config_rp as Field;

let mut count = 0;

for _r in 0..rf/2 // First half of full rounds
{
for i in 0..array::len(state)
{
state[i] = state[i] + ark[count + i];
} // Shift by round constants

for i in 0..array::len(state)
{
state[i] = pow_32(state[i], alpha);
}

state = apply_matrix(mds, state); // Apply MDS matrix
count = count + t;
}

for _r in 0..rp // Partial rounds
{
for i in 0..array::len(state)
{
state[i] = state[i] + ark[count + i];
} // Shift by round constants

state[0] = pow_32(state[0], alpha);

state = apply_matrix(mds, state); // Apply MDS matrix
count = count + t;
}

for _r in 0..rf/2 // Second half of full rounds
{
for i in 0..array::len(state)
{
state[i] = state[i] + ark[count + i];
} // Shift by round constants

for i in 0..array::len(state)
{
state[i] = pow_32(state[i], alpha);
}

state = apply_matrix(mds, state); // Apply MDS matrix
count = count + t;
}

state
}

// Corresponding absorption.
fn absorb<M,N,O,P>(pos_conf: PoseidonConfig<M, N>,
mut state: [Field; O], // Initial state; usually [0; N]
rate: comptime Field, // Rate
capacity: comptime Field, // Capacity; usually 1
msg: [Field; P] // Arbitrary length message
) -> [Field; O]
{

constrain pos_conf.t == rate + capacity;

let mut i = 0;

for k in 0..array::len(msg)
{
// Add current block to state
state[capacity + i] += msg[k];
i = i+1;
if i == rate // Enough to absorb
{
state = permute(pos_conf, state);
i = 0;
}
};

if i > 0 // If we have one more block to permute
{
state = permute(pos_conf, state);
}

state
}

// Variable-length Poseidon-128 sponge as suggested in second bullet point of §3 of https://eprint.iacr.org/2019/458.pdf
fn sponge<N>(msg: [Field; N]) -> Field // Poseidon sponge (absorption) with rate 4 and width 5
{
crate::hash::poseidon::absorb(consts::rf, consts::rp()[3], consts::alpha, consts::ark5(), consts::mds5(), [0;5], 4, 1, msg)[1]
absorb(consts::x5_5_config(), [0;5], 4, 1, msg)[1]
}
203 changes: 86 additions & 117 deletions noir_stdlib/src/hash/poseidon/bn254/consts.nr

Large diffs are not rendered by default.

Loading

0 comments on commit 6992c54

Please sign in to comment.