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
.idea
Cargo.lock
/target
/tmp

View File

@ -9,6 +9,7 @@ Hash functions implemented:
- [x] Poseidon2
- [x] Griffin
- [x] skyscraper
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

View File

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

View File

@ -7,3 +7,4 @@ pub mod hash;
pub mod poseidon2;
pub mod griffin;
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]);
}
}