impl skyscraper

This commit is contained in:
M Alghazwi 2025-01-28 14:12:59 +01:00
parent 0db2f80df0
commit 88a662f034
7 changed files with 241 additions and 1 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
.DS_Store .DS_Store
.idea
Cargo.lock Cargo.lock
/target /target
/tmp /tmp

View File

@ -9,6 +9,7 @@ Hash functions implemented:
- [x] Poseidon2 - [x] Poseidon2
- [x] Griffin - [x] Griffin
- [x] skyscraper
We plan to integrate this into Plonky2, to allow an efficient BN254 recursive wrapper. We plan to integrate this into Plonky2, to allow an efficient BN254 recursive wrapper.
For this we need some custom features: For example when computing the Fiat-Shamir For this we need some custom features: For example when computing the Fiat-Shamir

View File

@ -3,7 +3,7 @@ use ark_ff::prelude::{Zero};
use ark_bn254::Fr as F; use ark_bn254::Fr as F;
use crate::state::*; use crate::state::*;
use crate::poseidon2; use crate::{poseidon2, skyscraper};
use crate::griffin; use crate::griffin;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -7,3 +7,4 @@ pub mod hash;
pub mod poseidon2; pub mod poseidon2;
pub mod griffin; pub mod griffin;
pub mod sponge; pub mod sponge;
pub mod skyscraper;

View File

@ -0,0 +1,90 @@
use std::str::FromStr;
use lazy_static::lazy_static;
use ark_bn254::Fr as F;
use ark_ff::BigInteger256;
/// enum for deciding which function (Square or Bar) to apply
#[derive(Clone, Copy, Debug)]
pub enum FunctionBlock {
Square,
Bar,
}
/// round schedule
pub static RF1: [FunctionBlock; 10] = [
FunctionBlock::Square, FunctionBlock::Square,
FunctionBlock::Bar, FunctionBlock::Bar,
FunctionBlock::Square, FunctionBlock::Square,
FunctionBlock::Bar, FunctionBlock::Bar,
FunctionBlock::Square, FunctionBlock::Square,
];
/// round constants - same as in:
/// https://extgit.isec.tugraz.at/krypto/zkfriendlyhashzoo/-/blob/master/plain_impls/src/skyscraper/skyscraper_instances.rs?ref_type=heads
static RC_STR: [&str; 24] = [
"17829420340877239108687448009732280677191990375576158938221412342251481978692",
"27740342931201890067831390843279536630457710544396725670188095857896839417202",
"17048088173265532689680903955395019356591870902241717143279822196003888806966",
"109512792282736997633398631034649037613028427788284511060520396554381700616124",
"23518768991468467328187394347260979305359711922005254253047385842741274989784",
"95360373645575887695357714105933674592754581048282220961740831584356266637451",
"57106046715138585370392400429108362862843547132381623658436718362793140581845",
"16971509144034029782226530622087626979814683266929655790026304723118124142299",
"8608910393531852188108777530736778805001620473682472554749734455948859886057",
"54566392379700209585884878067585451869449334062644668287971552334629853792764",
"18708129585851494907644197977764586873688181219062643217509404046560774277231",
"52159802752268413629255578890890486811485406260370834838036769779232029980820",
"98108525134123848500172941527936985409086875223276518679938863940387852105202",
"105831033594660236721345339515389948186304708551041643590872398526195732523291",
"53084450331558915295247017186532447841918727727492403087452333633170905880952",
"78730946611419899835403512890231154575719512053287438310527615801825503526967",
"62089842541186043938517187437087053794210809382724083686360536771123796704819",
"32303085017979849099049635709265581104054174293154472699090841350494692332148",
"19361794324495443451354916303398190341881571975219162871160427826227778850994",
"65021267664773559966759214868166670507376995901124257419858229816098767301789",
"94847021352352647235478120180321422709509900436733319635143815989658015262598",
"51591271359432809566841356156562526830388219805637947403945613063492005256674",
"44534956566050763472510245910556224585100739093572801527559057220740673520964",
"84085239597197409225577945757724209425761279846653606664394225962327262179862",
];
/// same as above but in raw representation (just for checking consistency)
static RC_STR_RAW: [&str; 24] = [
"17829420340877239108687448009732280677191990375576158938221412342251481978692",
"5852100059362614845584985098022261541909346143980691326489891671321030921585",
"17048088173265532689680903955395019356591870902241717143279822196003888806966",
"71577923540621522166602308362662170286605786204339342029375621502658138039",
"1630526119629192105940988602003704216811347521589219909349181656165466494167",
"7807402158218786806372091124904574238561123446618083586948014838053032654983",
"13329560971460034925899588938593812685746818331549554971040309989641523590611",
"16971509144034029782226530622087626979814683266929655790026304723118124142299",
"8608910393531852188108777530736778805001620473682472554749734455948859886057",
"10789906636021659141392066577070901692352605261812599600575143961478236801530",
"18708129585851494907644197977764586873688181219062643217509404046560774277231",
"8383317008589863184762767400375936634388677459538766150640361406080412989586",
"10555553646766747611187318546907885054893417621612381305146047194084618122734",
"18278062107303135832359716534360847832111250949377506216079581779892498540823",
"9307964587880364850754205696017897664821998926660334400055925260019288889718",
"13066217995902074168664295654459329310074418852039335279433003242098078040116",
"18313356797507493494024375946572503617114080581892014998964128397972179713585",
"10414842146140573876803229964008306015505809892738438355392637163918883836531",
"19361794324495443451354916303398190341881571975219162871160427826227778850994",
"21244781921095009522266403377652120330280267100292188732461821442947150310555",
"7294049864995546346492497199292322355316442835069182260350999243354781280130",
"7814785615754259122348544666047976653291491004805878716549204690340388265440",
"758470822372213028017434420041674408004010292740732840162648847589056529730",
"18420510981679583558838728521952384160116186645405503633299613402599836693011",
];
lazy_static! {
pub static ref RC: Vec<F> = RC_STR
.iter()
.map(|s| F::new_unchecked(BigInteger256::from_str(s).unwrap()))
.collect();
pub static ref RC_RAW: Vec<F> = RC_STR_RAW
.iter()
.map(|s| F::new_unchecked(BigInteger256::from_str(s).unwrap()))
.collect();
}

2
src/skyscraper/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod permutation;
mod constants;

View File

@ -0,0 +1,145 @@
use ark_bn254::{Fr as F};
use ark_ff::{BigInteger256, Field, One, PrimeField};
use core::str::FromStr;
use crate::skyscraper::constants::{FunctionBlock, RF1, RC, RC_RAW};
pub fn bars_inplace_mont(x: &mut F) {
// x → two 128bit chunks.
let bi = x.0;
let limbs = bi.0;
let mut data = [0u128; 2];
data[0] = (limbs[0] as u128) | ((limbs[1] as u128) << 64);
data[1] = (limbs[2] as u128) | ((limbs[3] as u128) << 64);
let t_function = |value: u128| {
let t1 = ((value & 0x80808080808080808080808080808080) >> 7) | ((value & 0x7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F) << 1); //circular left rot by 1
let t2 = ((value & 0xC0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0) >> 6) | ((value & 0x3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F) << 2); //circular left rot by 2
let t3 = ((value & 0xE0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0) >> 5) | ((value & 0x1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F1F) << 3); //circular left rot by 3
let tmp = (!t1 & t2 & t3) ^ value;
((tmp & 0x80808080808080808080808080808080) >> 7) | ((tmp & 0x7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F) << 1) // Final left rot by 1
};
// Tfunction to each chunk.
let tmp_lo = t_function(data[1]);
let tmp_hi = t_function(data[0]);
data[0] = tmp_lo;
data[1] = tmp_hi;
// reduce
reduce_small::<F>(&mut data);
// put back into x
let (lo, hi) = (data[0], data[1]);
let mut out = BigInteger256::new([0, 0, 0, 0]);
out.0[0] = (lo & 0xFFFFFFFFFFFFFFFF) as u64;
out.0[1] = (lo >> 64) as u64;
out.0[2] = (hi & 0xFFFFFFFFFFFFFFFF) as u64;
out.0[3] = (hi >> 64) as u64;
*x = F::new_unchecked(out)
}
// same reduction strategy as in the zkfriendlyhashzoo
fn reduce_small<F: PrimeField>(lhs: &mut [u128; 2]) {
let p = F::characteristic(); // same as Modulus
let pa = p.as_ref();
// prime in two 128bit limbs
let mut prime = [0u128; 2];
prime[0] = (pa[0] as u128) | ((pa[1] as u128) << 64);
prime[1] = (pa[2] as u128) | ((pa[3] as u128) << 64);
loop {
for idx in (0..2).rev() {
if lhs[idx] < prime[idx] {
return;
}
if lhs[idx] > prime[idx] {
sub_full(lhs, &prime);
break;
}
if idx == 0 && lhs[idx] == prime[idx] {
lhs[0] = 0;
lhs[1] = 0;
return;
}
}
}
}
pub fn sub_full(lhs: &mut [u128], rhs: &[u128]) {
let mut overflow: bool;
let mut overflow_part: u128;
(lhs[0], overflow) = lhs[0].overflowing_sub(rhs[0]);
overflow_part = if overflow {1} else {0};
for index in 1..rhs.len(){
(lhs[index], overflow) = lhs[index].overflowing_sub(overflow_part);
overflow_part = if overflow {1} else {0};
(lhs[index], overflow) = lhs[index].overflowing_sub(rhs[index]);
incr(&mut overflow_part, overflow);
}
}
#[inline(always)]
pub fn incr(left: &mut u128, right: bool){
if right {
*left += 1;
}
}
fn square_inplace(x: &mut F) {
*x *= *x;
}
pub fn permute(input: [F; 2]) -> [F; 2] {
let mut current_state = input;
let mut left = current_state[0];
let mut right = current_state[1];
for (i, &fun) in RF1.iter().enumerate() {
// sbox on `left`
match fun {
FunctionBlock::Square => square_inplace(&mut left),
FunctionBlock::Bar => bars_inplace_mont(&mut left),
}
if i > 0 && i < (RF1.len() - 1) {
right += RC_RAW[i - 1];
}
// combine
left += right;
// the feistel rotation
right = current_state[0];
current_state[0] = left;
}
current_state[1] = right;
current_state
}
pub fn compress(x: F, y: F) -> F {
let p_out = permute([x, y]);
let out = x + p_out[0];
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_k_permutation() {
let init = [F::from(1234u64), F::from(5678u64)];
let init_mont = [F::new_unchecked(init[0].into_bigint()), F::new_unchecked(init[1].into_bigint())];
let out = permute(init_mont);
println!("Permutation on (1234,5678) => ({},{})", out[0].0, out[1].0);
let expected = [
BigInteger256::from_str("10398388528337208913702213361515546865573572771332206462397283188708690721181").unwrap(),
BigInteger256::from_str("21827939006013637437091304277086947125806852726479468249428384625000968262245").unwrap()
];
assert_eq!(out[0].0, expected[0]);
assert_eq!(out[1].0, expected[1]);
}
}