From 53097e8d9fea058490c53bf8a6189a6a6aa2fbf6 Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Sun, 8 Jun 2025 20:30:30 +0100 Subject: [PATCH 1/8] Implement blake2s hasher and sparse address --- packages/sphincs-plus/src/address.cairo | 151 +++--------------- packages/sphincs-plus/src/address/dense.cairo | 146 +++++++++++++++++ .../sphincs-plus/src/address/sparse.cairo | 114 +++++++++++++ packages/sphincs-plus/src/fors.cairo | 16 +- packages/sphincs-plus/src/hasher.cairo | 47 +++--- .../sphincs-plus/src/hasher/blake2s.cairo | 71 ++++++++ .../src/{sha2.cairo => hasher/sha256.cairo} | 14 +- packages/sphincs-plus/src/lib.cairo | 1 - packages/sphincs-plus/src/sphincs.cairo | 16 +- packages/sphincs-plus/src/wots.cairo | 29 ++-- 10 files changed, 423 insertions(+), 182 deletions(-) create mode 100644 packages/sphincs-plus/src/address/dense.cairo create mode 100644 packages/sphincs-plus/src/address/sparse.cairo create mode 100644 packages/sphincs-plus/src/hasher/blake2s.cairo rename packages/sphincs-plus/src/{sha2.cairo => hasher/sha256.cairo} (95%) diff --git a/packages/sphincs-plus/src/address.cairo b/packages/sphincs-plus/src/address.cairo index c3e8bea..1697b66 100644 --- a/packages/sphincs-plus/src/address.cairo +++ b/packages/sphincs-plus/src/address.cairo @@ -2,46 +2,15 @@ // // SPDX-License-Identifier: MIT -//! Address structure aligned for use with SHA2/Blake2s hash functions. -//! See https://www.di-mgt.com.au/pqc-09-fors-sig.html for layout details. +// Available address implementations. +mod dense; +mod sparse; -use crate::word_array::{WordArray, WordArrayTrait}; +// Select the chosen Address implementation +pub use dense::Address; +use crate::word_array::WordArray; -/// FORS address layout: -/// 0 4 8 12 16 20 -/// [0 111] [1111] [1 2 xx] [3 3 xx] [x 4 55] [55] -/// -/// WOTS address layout: -/// 0 4 8 12 16 20 -/// [0 111] [1111] [1 2 xx] [3 3 xx] [x 6 xx] [x 7] -/// -/// Where: -/// 0. Hypertree layer (1 byte) -/// 1. Hypertree address (8 bytes) -/// 2. Address type (1 byte) -/// 3. Keypair hi/lo (2 bytes) -/// 4. Tree height (1 byte) -/// 5. Tree index (4 bytes) -/// 6. Wots chain address (1 byte) -/// 7. Wots hash address (1 byte) -#[derive(Drop, Copy, Default, Debug)] -pub struct Address { - w0: u32, // layer, hypertree address - w1: u32, // hypertree address - w2: u32, // hypertree address, address type - w3: u32, // keypair high/low bytes - w4: u32, // tree height | wots chain address - w5: u32, // tree index | wots hash address (we use lower bytes) - // Cached values - w0_a: u32, - w0_bcd: u32, - w2_a: u32, - w2_b: u32, - w4_b: u32, - w4_cd: u32, -} - -#[derive(Drop, Copy)] +#[derive(Drop)] pub enum AddressType { WOTS, // 0 WOTSPK, // 1 @@ -52,79 +21,19 @@ pub enum AddressType { FORSPRF // 6 } -#[generate_trait] -pub impl AddressImpl of AddressTrait { - fn from_components(w0: u32, w1: u32, w2: u32, w3: u32, w4: u32, w5: u32) -> Address { - let (w0_a, w0_bcd) = DivRem::div_rem(w0, 0x1000000); - let (w2_a, w2_b) = DivRem::div_rem(w2 / 0x10000, 0x100); - let (w4_b, w4_cd) = DivRem::div_rem(w4 % 0x1000000, 0x10000); - Address { w0, w1, w2, w3, w4, w5, w0_a, w0_bcd, w2_a, w2_b, w4_b, w4_cd } - } - - fn set_hypertree_layer(ref self: Address, layer: u8) { - self.w0_a = layer.into() * 0x1000000; - self.w0 = self.w0_a + self.w0_bcd; - } - - fn set_hypertree_address(ref self: Address, tree_address: u64) { - let (abc, defgh) = DivRem::div_rem(tree_address, 0x10000000000); - let (defg, h) = DivRem::div_rem(defgh, 0x100); - self.w0_bcd = abc.try_into().unwrap(); - self.w0 = self.w0_a + self.w0_bcd; - self.w1 = defg.try_into().unwrap(); - self.w2_a = h.try_into().unwrap() * 0x1000000; - // we don't care about the lowest 2 bytes (they are not used and set to zero) - self.w2 = self.w2_a + self.w2_b; - } - - fn set_address_type(ref self: Address, address_type: AddressType) { - self.w2_b = address_type.into() * 0x10000; - // we don't care about the lowest 2 bytes (they are not used and set to zero) - self.w2 = self.w2_a + self.w2_b; - } - - fn set_keypair(ref self: Address, keypair: u16) { - // we don't care about the lowest 2 bytes (they are not used and set to zero) - self.w3 = keypair.into() * 0x10000; - } - - fn set_tree_height(ref self: Address, tree_height: u8) { - self.w4_b = tree_height.into() * 0x10000; - // we don't care about the highest byte (it is not used and set to zero) - self.w4 = self.w4_b + self.w4_cd; - } - - fn set_tree_index(ref self: Address, tree_index: u32) { - let (ab, cd) = DivRem::div_rem(tree_index, 0x10000); - self.w4_cd = ab; - // we don't care about the highest byte (it is not used and set to zero) - self.w4 = self.w4_b + self.w4_cd; - // we use lower bytes for compatibility with [WordArray] - self.w5 = cd; - } - - fn set_chain_address(ref self: Address, chain_address: u8) { - // In WOTS address other bytes are not used and set to zero. - self.w4_b = chain_address.into() * 0x10000; - // Other bytes are unused - self.w4 = self.w4_b - } - - fn set_hash_address(ref self: Address, hash_address: u8) { - // In WOTS address other bytes are not used and set to zero. - // We use lower bytes for compatibility with [WordArray] - self.w5 = hash_address.into(); - } - - fn to_word_array(self: Address) -> WordArray { - WordArrayTrait::new(array![self.w0, self.w1, self.w2, self.w3, self.w4], self.w5, 2) - } -} - -impl AddressTypeDefault of Default { - fn default() -> AddressType { - AddressType::WOTS - } +pub trait AddressTrait { + fn set_hypertree_layer(ref self: T, layer: u8); + fn set_hypertree_addr(ref self: T, tree_address: u64); + fn set_address_type(ref self: T, address_type: AddressType); + fn set_keypair(ref self: T, keypair: u16); + fn set_tree_height(ref self: T, tree_height: u8); + fn set_tree_index(ref self: T, tree_index: u32); + fn set_wots_chain_addr(ref self: T, chain_address: u8); + fn set_wots_hash_addr(ref self: T, hash_address: u8); + fn to_word_array(self: @T) -> WordArray; + + #[cfg(test)] + fn from_components(components: Array) -> T; } impl AddressTypeToU32 of Into { @@ -141,22 +50,8 @@ impl AddressTypeToU32 of Into { } } -#[cfg(test)] -mod tests { - use crate::word_array::hex::words_to_hex; - use super::*; - - #[test] - fn test_fors_tree_address() { - let mut address: Address = Default::default(); - address.set_hypertree_layer(0); - address.set_hypertree_address(14512697849565227); - address.set_address_type(AddressType::FORSTREE); - address.set_keypair(102); - address.set_tree_height(0); - address.set_tree_index(2765); - let res = words_to_hex(address.to_word_array().span()); - let expected = "0000338f38c80e502b03000000660000000000000acd"; - assert_eq!(res, expected); +impl AddressTypeDefault of Default { + fn default() -> AddressType { + AddressType::WOTS } } diff --git a/packages/sphincs-plus/src/address/dense.cairo b/packages/sphincs-plus/src/address/dense.cairo new file mode 100644 index 0000000..e2c3de8 --- /dev/null +++ b/packages/sphincs-plus/src/address/dense.cairo @@ -0,0 +1,146 @@ +// SPDX-FileCopyrightText: 2025 StarkWare Industries Ltd. +// +// SPDX-License-Identifier: MIT + +//! Address structure aligned for use with SHA2/Blake2s hash functions. +//! See https://www.di-mgt.com.au/pqc-09-fors-sig.html for layout details. + +use crate::word_array::{WordArray, WordArrayTrait}; +use super::{AddressTrait, AddressType}; + +/// Generic address layout: +/// 0 4 8 12 16 20 +/// [0 111] [1111] [1 2 xx] [3 3 xx] [x 4 55] [55] +/// +/// WOTS address layout: +/// 0 4 8 12 16 20 +/// [0 111] [1111] [1 2 xx] [3 3 xx] [x 6 xx] [x 7] +/// +/// Where: +/// 0. Hypertree layer (1 byte) +/// 1. Hypertree address (8 bytes) +/// 2. Address type (1 byte) +/// 3. Keypair hi/lo (2 bytes) +/// 4. Tree height (1 byte) +/// 5. Tree index (4 bytes) +/// 6. Wots chain address (1 byte) +/// 7. Wots hash address (1 byte) +#[derive(Drop, Clone, Default, Debug)] +pub struct Address { + w0: u32, // layer, hypertree address + w1: u32, // hypertree address + w2: u32, // hypertree address, address type + w3: u32, // keypair high/low bytes + w4: u32, // tree height | wots chain address + w5: u32, // tree index | wots hash address (we use lower bytes) + // Cached values + w0_a: u32, + w0_bcd: u32, + w2_a: u32, + w2_b: u32, + w4_b: u32, + w4_cd: u32, +} + +#[cfg(test)] +pub fn from_components(w0: u32, w1: u32, w2: u32, w3: u32, w4: u32, w5: u32) -> Address { + let (w0_a, w0_bcd) = DivRem::div_rem(w0, 0x1000000); + let (w2_a, w2_b) = DivRem::div_rem(w2 / 0x10000, 0x100); + let (w4_b, w4_cd) = DivRem::div_rem(w4 % 0x1000000, 0x10000); + Address { w0, w1, w2, w3, w4, w5, w0_a, w0_bcd, w2_a, w2_b, w4_b, w4_cd } +} + +pub impl AddressImpl of AddressTrait
{ + #[cfg(test)] + fn from_components(mut components: Array) -> Address { + let w0 = components.pop_front().unwrap(); + let w1 = components.pop_front().unwrap(); + let w2 = components.pop_front().unwrap(); + let w3 = components.pop_front().unwrap(); + let w4 = components.pop_front().unwrap(); + let w5 = components.pop_front().unwrap(); + let (w0_a, w0_bcd) = DivRem::div_rem(w0, 0x1000000); + let (w2_a, w2_b) = DivRem::div_rem(w2 / 0x10000, 0x100); + let (w4_b, w4_cd) = DivRem::div_rem(w4 % 0x1000000, 0x10000); + Address { w0, w1, w2, w3, w4, w5, w0_a, w0_bcd, w2_a, w2_b, w4_b, w4_cd } + } + + fn set_hypertree_layer(ref self: Address, layer: u8) { + self.w0_a = layer.into() * 0x1000000; + self.w0 = self.w0_a + self.w0_bcd; + } + + fn set_hypertree_addr(ref self: Address, tree_address: u64) { + let (abc, defgh) = DivRem::div_rem(tree_address, 0x10000000000); + let (defg, h) = DivRem::div_rem(defgh, 0x100); + self.w0_bcd = abc.try_into().unwrap(); + self.w0 = self.w0_a + self.w0_bcd; + self.w1 = defg.try_into().unwrap(); + self.w2_a = h.try_into().unwrap() * 0x1000000; + // we don't care about the lowest 2 bytes (they are not used and set to zero) + self.w2 = self.w2_a + self.w2_b; + } + + fn set_address_type(ref self: Address, address_type: AddressType) { + self.w2_b = address_type.into() * 0x10000; + // we don't care about the lowest 2 bytes (they are not used and set to zero) + self.w2 = self.w2_a + self.w2_b; + } + + fn set_keypair(ref self: Address, keypair: u16) { + // we don't care about the lowest 2 bytes (they are not used and set to zero) + self.w3 = keypair.into() * 0x10000; + } + + fn set_tree_height(ref self: Address, tree_height: u8) { + self.w4_b = tree_height.into() * 0x10000; + // we don't care about the highest byte (it is not used and set to zero) + self.w4 = self.w4_b + self.w4_cd; + } + + fn set_tree_index(ref self: Address, tree_index: u32) { + let (ab, cd) = DivRem::div_rem(tree_index, 0x10000); + self.w4_cd = ab; + // we don't care about the highest byte (it is not used and set to zero) + self.w4 = self.w4_b + self.w4_cd; + // we use lower bytes for compatibility with [WordArray] + self.w5 = cd; + } + + fn set_wots_chain_addr(ref self: Address, chain_address: u8) { + // In WOTS address other bytes are not used and set to zero. + self.w4_b = chain_address.into() * 0x10000; + // Other bytes are unused + self.w4 = self.w4_b + } + + fn set_wots_hash_addr(ref self: Address, hash_address: u8) { + // In WOTS address other bytes are not used and set to zero. + // We use lower bytes for compatibility with [WordArray] + self.w5 = hash_address.into(); + } + + fn to_word_array(self: @Address) -> WordArray { + WordArrayTrait::new(array![*self.w0, *self.w1, *self.w2, *self.w3, *self.w4], *self.w5, 2) + } +} + +#[cfg(test)] +mod tests { + use crate::word_array::hex::words_to_hex; + use super::*; + + #[test] + fn test_fors_tree_address() { + let mut address: Address = Default::default(); + address.set_hypertree_layer(0); + address.set_hypertree_addr(14512697849565227); + address.set_address_type(AddressType::FORSTREE); + address.set_keypair(102); + address.set_tree_height(0); + address.set_tree_index(2765); + let res = words_to_hex(address.to_word_array().span()); + let expected = "0000338f38c80e502b03000000660000000000000acd"; + assert_eq!(res, expected); + } +} diff --git a/packages/sphincs-plus/src/address/sparse.cairo b/packages/sphincs-plus/src/address/sparse.cairo new file mode 100644 index 0000000..76b2a65 --- /dev/null +++ b/packages/sphincs-plus/src/address/sparse.cairo @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: 2025 StarkWare Industries Ltd. +// +// SPDX-License-Identifier: MIT + +//! Address structure aligned for use with SHA2/Blake2s hash functions. +//! See https://www.di-mgt.com.au/pqc-09-fors-sig.html for layout details. + +use crate::word_array::{WordArray, WordArrayTrait}; +use super::{AddressTrait, AddressType}; + +/// Simplified address layout +#[derive(Drop, Default, Debug)] +pub struct Address { + layer: u32, + hypertree_addr_hi: u32, + hypertree_addr_lo: u32, + address_type: u32, + keypair: u32, + tree_height: u32, + tree_index: u32, + wots_chain_addr: u32, + wots_hash_addr: u32, +} + +pub impl AddressImpl of AddressTrait
{ + #[cfg(test)] + fn from_components(mut components: Array) -> Address { + let layer = components.pop_front().unwrap(); + let hypertree_addr_hi = components.pop_front().unwrap(); + let hypertree_addr_lo = components.pop_front().unwrap(); + let address_type = components.pop_front().unwrap(); + let keypair = components.pop_front().unwrap(); + let tree_height = components.pop_front().unwrap(); + let tree_index = components.pop_front().unwrap(); + let wots_chain_addr = components.pop_front().unwrap(); + let wots_hash_addr = components.pop_front().unwrap(); + Address { + layer, + hypertree_addr_hi, + hypertree_addr_lo, + address_type, + keypair, + tree_height, + tree_index, + wots_chain_addr, + wots_hash_addr, + } + } + + fn set_hypertree_layer(ref self: Address, layer: u8) { + self.layer = layer.into(); + } + + fn set_hypertree_addr(ref self: Address, tree_address: u64) { + let (hi, lo) = DivRem::div_rem(tree_address, 0x100000000); + self.hypertree_addr_hi = hi.try_into().unwrap(); + self.hypertree_addr_lo = lo.try_into().unwrap(); + } + + fn set_address_type(ref self: Address, address_type: AddressType) { + self.address_type = address_type.into(); + } + + fn set_keypair(ref self: Address, keypair: u16) { + self.keypair = keypair.into(); + } + + fn set_tree_height(ref self: Address, tree_height: u8) { + self.tree_height = tree_height.into(); + } + + fn set_tree_index(ref self: Address, tree_index: u32) { + self.tree_index = tree_index; + } + + fn set_wots_chain_addr(ref self: Address, chain_address: u8) { + self.wots_chain_addr = chain_address.into(); + } + + fn set_wots_hash_addr(ref self: Address, hash_address: u8) { + self.wots_hash_addr = hash_address.into(); + } + + fn to_word_array(self: @Address) -> WordArray { + WordArrayTrait::new( + array![ + *self.layer, + *self.hypertree_addr_hi, + *self.hypertree_addr_lo, + *self.address_type, + *self.keypair, + *self.tree_height, + *self.tree_index, + *self.wots_chain_addr, + *self.wots_hash_addr, + ], + 0, + 0, + ) + } +} + +impl AddressClone of Clone
{ + fn clone(self: @Address) -> Address { + Address { + layer: *self.layer, + hypertree_addr_hi: *self.hypertree_addr_hi, + hypertree_addr_lo: *self.hypertree_addr_lo, + address_type: *self.address_type, + keypair: *self.keypair, + ..Default::default(), + } + } +} diff --git a/packages/sphincs-plus/src/fors.cairo b/packages/sphincs-plus/src/fors.cairo index 20c3efc..cdc1dcb 100644 --- a/packages/sphincs-plus/src/fors.cairo +++ b/packages/sphincs-plus/src/fors.cairo @@ -24,12 +24,9 @@ pub struct ForsTreeSignature { /// Derive FORS public key from a signature. pub fn fors_pk_from_sig( - ctx: SpxCtx, mut sig: ForsSignature, mhash: WordSpan, address: Address, + ctx: SpxCtx, mut sig: ForsSignature, mhash: WordSpan, address: @Address, ) -> HashOutput { - let mut fors_pk_addr = address; - let mut fors_tree_addr = address; - - fors_pk_addr.set_address_type(AddressType::FORSPK); + let mut fors_tree_addr = address.clone(); fors_tree_addr.set_address_type(AddressType::FORSTREE); // Compute indices of leaves of the FORS trees @@ -49,18 +46,21 @@ pub fn fors_pk_from_sig( fors_tree_addr.set_tree_index(idx_offset + leaf_idx); // Derive the leaf hash from the secret key seed and tree address. - let leaf = thash_128s(ctx, fors_tree_addr, sk_seed.span()); + let leaf = thash_128s(ctx, @fors_tree_addr, sk_seed.span()); // Derive the corresponding root node of this tree. // Auth path has fixed length, so we don't need to assert tree height. - let root = compute_root(ctx, fors_tree_addr, leaf, auth_path.span(), leaf_idx, idx_offset); + let root = compute_root(ctx, @fors_tree_addr, leaf, auth_path.span(), leaf_idx, idx_offset); roots.append_span(root.span()); idx_offset += SPX_FORS_BASE_OFFSET; } // Hash horizontally across all tree roots to derive the public key. - thash_128s(ctx, fors_pk_addr, roots.span()) + let mut fors_pk_addr = address.clone(); + fors_pk_addr.set_address_type(AddressType::FORSPK); + + thash_128s(ctx, @fors_pk_addr, roots.span()) } /// Convert FORS mhash to leaves indices. diff --git a/packages/sphincs-plus/src/hasher.cairo b/packages/sphincs-plus/src/hasher.cairo index c066723..c6827fe 100644 --- a/packages/sphincs-plus/src/hasher.cairo +++ b/packages/sphincs-plus/src/hasher.cairo @@ -2,17 +2,23 @@ // // SPDX-License-Identifier: MIT +// Available hash functions. +mod blake2s; +mod sha256; + +// Select the hash function to use. +pub use sha256::{HashState, hash_finalize, hash_init, hash_update}; use crate::address::{Address, AddressTrait, AddressType}; use crate::params_128s::SPX_HASH_LEN; -use crate::sha2::{Sha256State, sha256_inc_finalize, sha256_inc_init, sha256_inc_update}; use crate::word_array::{WordArray, WordArrayTrait, WordSpan, WordSpanTrait}; /// Hash output. pub type HashOutput = [u32; SPX_HASH_LEN]; +/// Hash context. #[derive(Drop, Copy, Default, Debug)] pub struct SpxCtx { - pub state_seeded: Sha256State, + pub state_seeded: HashState, } /// Absorb the constant pub_seed using one round of the compression function @@ -22,19 +28,19 @@ pub fn initialize_hash_function(pk_seed: HashOutput) -> SpxCtx { let mut data = pk_seed.span().into(); data.append_span(array![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0].span()); - let mut state: Sha256State = Default::default(); - sha256_inc_init(ref state); - sha256_inc_update(ref state, data.span()); + let mut state: HashState = Default::default(); + hash_init(ref state); + hash_update(ref state, data.span()); SpxCtx { state_seeded: state } } /// Compute a truncated hash of the data. -pub fn thash_128s(ctx: SpxCtx, address: Address, input: Span) -> HashOutput { +pub fn thash_128s(ctx: SpxCtx, address: @Address, input: Span) -> HashOutput { let mut buffer = address.to_word_array(); buffer.append_u32_span(input); let (words, last_word, last_word_len) = buffer.into_components(); - let [d0, d1, d2, d3, _, _, _, _] = sha256_inc_finalize( + let [d0, d1, d2, d3, _, _, _, _] = hash_finalize( ctx.state_seeded, words, last_word, last_word_len, ); [d0, d1, d2, d3] @@ -58,11 +64,11 @@ pub fn hash_message_128s( let (msg_words, msg_last_word, msg_last_word_len) = message.into_components(); data.append_span(msg_words); - let mut state: Sha256State = Default::default(); - sha256_inc_init(ref state); + let mut state: HashState = Default::default(); + hash_init(ref state); // Compute the seed for XOF. - let seed = sha256_inc_finalize(state, data, msg_last_word, msg_last_word_len); + let seed = hash_finalize(state, data, msg_last_word, msg_last_word_len); let mut xof_data: Array = array![]; xof_data.append_span(randomizer.span()); @@ -71,7 +77,7 @@ pub fn hash_message_128s( xof_data.append(0); // MGF1 counter = 0 // Apply MGF1 to the seed. - let mut buffer = sha256_inc_finalize(state, xof_data.into(), 0, 0).span(); + let mut buffer = hash_finalize(state, xof_data.into(), 0, 0).span(); // Construct the digest from the extended output. // NOTE: we haven't cleared the LSB of the last word, has to be handled correctly. @@ -86,7 +92,7 @@ pub fn hash_message_128s( /// Compute the root of a tree given the leaf and the authentication path. pub fn compute_root( ctx: SpxCtx, - mut address: Address, + address: @Address, leaf: HashOutput, mut auth_path: Span, mut leaf_idx: u32, @@ -94,6 +100,7 @@ pub fn compute_root( ) -> HashOutput { let mut node = leaf; let mut i = 0; + let mut address = address.clone(); while let Some(hash_witness) = auth_path.pop_front() { let (q, r) = DivRem::div_rem(leaf_idx, 2); @@ -114,7 +121,7 @@ pub fn compute_root( address.set_tree_height(i); address.set_tree_index(leaf_idx + idx_offset); - node = thash_128s(ctx, address, buffer.span()); + node = thash_128s(ctx, @address, buffer.span()); } node @@ -152,7 +159,7 @@ mod tests { fn test_thash_128s() { let mut address: Address = Default::default(); address.set_hypertree_layer(0); - address.set_hypertree_address(0x002f1d1de40b58e8); + address.set_hypertree_addr(0x002f1d1de40b58e8); address.set_address_type(AddressType::FORSTREE); address.set_keypair(0x01f9); address.set_tree_height(0); @@ -163,16 +170,18 @@ mod tests { let (seed, _, _) = words_from_hex("d17096522c1d9de4e3c4c4e8659c1b86") .into_components(); // sk seed - let hash = thash_128s(Default::default(), address, seed.span()); + let hash = thash_128s(Default::default(), @address, seed.span()); assert_eq!(hash, [2384795752, 2382117612, 736107028, 3412802428]); } #[test] fn test_thash_128s_2() { - let address = AddressTrait::from_components(15967, 96104791, 956497920, 4849664, 0, 3481); + let address = AddressTrait::from_components( + array![15967, 96104791, 956497920, 4849664, 0, 3481], + ); let message = [3845349652, 3980556369, 2345842860, 1383522053]; let ctx = SpxCtx { - state_seeded: Sha256State { + state_seeded: HashState { h: ( 3428492436, 489272603, @@ -186,7 +195,7 @@ mod tests { byte_len: 64, }, }; - let digest = thash_128s(ctx, address, message.span()); + let digest = thash_128s(ctx, @address, message.span()); assert_eq!(digest, [629918136, 3883225718, 1150955665, 4167860371]); } @@ -224,7 +233,7 @@ mod tests { [1847957826, 195918516, 131309271, 2628527584], ]; let root = compute_root( - Default::default(), address, leaf, auth_path.span(), leaf_idx, idx_offset, + Default::default(), @address, leaf, auth_path.span(), leaf_idx, idx_offset, ); assert_eq!(root, [3756782339, 3014392485, 518995719, 3556760177]); } diff --git a/packages/sphincs-plus/src/hasher/blake2s.cairo b/packages/sphincs-plus/src/hasher/blake2s.cairo new file mode 100644 index 0000000..078f4bc --- /dev/null +++ b/packages/sphincs-plus/src/hasher/blake2s.cairo @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2025 StarkWare Industries Ltd. +// +// SPDX-License-Identifier: MIT + +use core::blake::{blake2s_compress, blake2s_finalize}; +use core::box::BoxImpl; + +const BLAKE2S_256_IV: [u32; 8] = [ + 0x6B08E647, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, +]; + +/// Blake2s incremental state. +#[derive(Debug, Drop, Copy)] +pub struct HashState { + pub h: Box<[u32; 8]>, + pub byte_len: u32, +} + +impl HashStateDefault of Default { + fn default() -> HashState { + HashState { h: BoxImpl::new([0; 8]), byte_len: 0 } + } +} + +/// Initializes the Blake2s hasher state with IV and resets the byte length. +pub fn hash_init(ref state: HashState) { + state.h = BoxImpl::new(BLAKE2S_256_IV); + state.byte_len = 0; +} + +/// Updates the Blake2s hasher state with the given data (data length must be a multiple of 16). +pub fn hash_update(ref state: HashState, mut data: Span) { + while let Some(chunk) = data.multi_pop_front::<16>() { + state.byte_len += 64; + blake2s_compress(state.h, state.byte_len, *chunk); + } + assert(data.is_empty(), 'unaligned blake2s block'); +} + +/// Finalizes the Blake2s hasher state and returns the hash. +pub fn hash_finalize( + mut state: HashState, input: Array, last_input_word: u32, last_input_num_bytes: u32, +) -> [u32; 8] { + let mut data = input.span(); + + while let Some(chunk) = data.multi_pop_front::<16>() { + state.byte_len += 64; + blake2s_compress(state.h, state.byte_len, *chunk); + } + + let mut buffer: Array = array![]; + buffer.append_span(data); + + if last_input_num_bytes == 1 { + buffer.append(last_input_word * 0x1000000); + } else if last_input_num_bytes == 2 { + buffer.append(last_input_word * 0x10000); + } else if last_input_num_bytes == 3 { + buffer.append(last_input_word * 0x100); + } + + for _ in buffer.len()..16 { + buffer.append(0); + } + + let msg = buffer.span().try_into().expect('Cast to @Blake2sInput failed'); + state.byte_len += 64; + + let res = blake2s_finalize(state.h, state.byte_len, *msg); + res.unbox() +} diff --git a/packages/sphincs-plus/src/sha2.cairo b/packages/sphincs-plus/src/hasher/sha256.cairo similarity index 95% rename from packages/sphincs-plus/src/sha2.cairo rename to packages/sphincs-plus/src/hasher/sha256.cairo index d6fa92b..f19ca7b 100644 --- a/packages/sphincs-plus/src/sha2.cairo +++ b/packages/sphincs-plus/src/hasher/sha256.cairo @@ -10,19 +10,19 @@ type T8 = (u32, u32, u32, u32, u32, u32, u32, u32); /// State of the SHA-256 hasher. #[derive(Debug, Drop, Copy, Default)] -pub struct Sha256State { +pub struct HashState { pub h: T8, pub byte_len: u32, } /// Initializes the SHA-256 hasher state with IV and resets the byte length. -pub fn sha256_inc_init(ref state: Sha256State) { +pub fn hash_init(ref state: HashState) { state.h = h; state.byte_len = 0; } /// Updates the SHA-256 hasher state with the given data (data length must be a multiple of 16). -pub fn sha256_inc_update(ref state: Sha256State, mut data: Span) { +pub fn hash_update(ref state: HashState, mut data: Span) { let data_len = data.len(); while let Some(chunk) = data.multi_pop_front::<16>() { state.h = sha256_inner(chunk.span(), state.h); @@ -39,8 +39,8 @@ pub fn sha256_inc_update(ref state: Sha256State, mut data: Span) { /// 3. Append the length of the array in bits as a 64-bit number. /// /// Use last_input_word when the number of bytes in the last input word is less than 4. -pub fn sha256_inc_finalize( - mut state: Sha256State, mut input: Array, last_input_word: u32, last_input_num_bytes: u32, +pub fn hash_finalize( + mut state: HashState, mut input: Array, last_input_word: u32, last_input_num_bytes: u32, ) -> [u32; 8] { state.byte_len += input.len() * 4 + last_input_num_bytes; @@ -273,7 +273,7 @@ mod tests { let buf = words_from_hex( "002e82f752b663241e060000000100000000000000047c9935a0b07694aa0c6d10e4db6b1add", ); - let mut state = Sha256State { + let mut state = HashState { h: ( 0x14163465, 0x04164476, @@ -293,7 +293,7 @@ mod tests { let (input, last_input_word, last_input_num_bytes) = buf.into_components(); - let res = sha256_inc_finalize(state, input, last_input_word, last_input_num_bytes); + let res = hash_finalize(state, input, last_input_word, last_input_num_bytes); assert_eq!(res, expected); } } diff --git a/packages/sphincs-plus/src/lib.cairo b/packages/sphincs-plus/src/lib.cairo index 6a1d253..bf8fee4 100644 --- a/packages/sphincs-plus/src/lib.cairo +++ b/packages/sphincs-plus/src/lib.cairo @@ -6,7 +6,6 @@ pub mod address; pub mod fors; pub mod hasher; pub mod params_128s; -pub mod sha2; pub mod sphincs; pub mod word_array; pub mod wots; diff --git a/packages/sphincs-plus/src/sphincs.cairo b/packages/sphincs-plus/src/sphincs.cairo index 85ae23f..c75e94d 100644 --- a/packages/sphincs-plus/src/sphincs.cairo +++ b/packages/sphincs-plus/src/sphincs.cairo @@ -59,37 +59,37 @@ pub fn verify_128s(message: WordSpan, sig: SphincsSignature, pk: SphincsPublicKe let mut wots_addr: Address = Default::default(); wots_addr.set_address_type(AddressType::WOTS); - wots_addr.set_hypertree_address(tree_address); + wots_addr.set_hypertree_addr(tree_address); wots_addr.set_keypair(leaf_idx); // Compute FORS public key (root) from the signature. - let mut root = fors_pk_from_sig(ctx, fors_sig, mhash, wots_addr); + let mut root = fors_pk_from_sig(ctx, fors_sig, mhash, @wots_addr); let mut layer: u8 = 0; let mut wots_merkle_sig_iter = wots_merkle_sig_list.span(); while let Some(WotsMerkleSignature { wots_sig, auth_path }) = wots_merkle_sig_iter.pop_front() { tree_addr.set_hypertree_layer(layer); - tree_addr.set_hypertree_address(tree_address); + tree_addr.set_hypertree_addr(tree_address); - wots_addr = tree_addr; + wots_addr = tree_addr.clone(); wots_addr.set_address_type(AddressType::WOTS); wots_addr.set_keypair(leaf_idx); - let mut wots_pk_addr = wots_addr; + let mut wots_pk_addr = wots_addr.clone(); wots_pk_addr.set_address_type(AddressType::WOTSPK); // The WOTS public key is only correct if the signature was correct. // Initially, root is the FORS pk, but on subsequent iterations it is // the root of the subtree below the currently processed subtree. - let wots_pk = wots_pk_from_sig(ctx, *wots_sig, root, wots_addr); + let wots_pk = wots_pk_from_sig(ctx, *wots_sig, root, @wots_addr); // Compute the leaf node using the WOTS public key. - let leaf = thash_128s(ctx, wots_pk_addr, wots_pk.span()); + let leaf = thash_128s(ctx, @wots_pk_addr, wots_pk.span()); // Compute the root node of this subtree. // Auth path has fixed length, so we don't need to assert tree height. - root = compute_root(ctx, tree_addr, leaf, auth_path.span(), leaf_idx.into(), 0); + root = compute_root(ctx, @tree_addr, leaf, auth_path.span(), leaf_idx.into(), 0); // Update the indices for the next layer. let (q, r) = DivRem::div_rem(tree_address, 0x200); // 1 << tree_height = 2^9 = 0x200 diff --git a/packages/sphincs-plus/src/wots.cairo b/packages/sphincs-plus/src/wots.cairo index b75e67b..828bdec 100644 --- a/packages/sphincs-plus/src/wots.cairo +++ b/packages/sphincs-plus/src/wots.cairo @@ -42,8 +42,10 @@ pub impl WotsSignatureDefault of Default { /// Takes a WOTS signature and an n-byte message, computes a WOTS public key. pub fn wots_pk_from_sig( - ctx: SpxCtx, sig: WotsSignature, message: HashOutput, mut address: Address, + ctx: SpxCtx, sig: WotsSignature, message: HashOutput, address: @Address, ) -> Array { + let mut wots_addr = address.clone(); + let mut lengths = base_w_128s(message.span()); add_checksum_128s(ref lengths); @@ -53,10 +55,10 @@ pub fn wots_pk_from_sig( let mut pk = array![]; while let Some(len) = lengths_iter.pop_front() { - address.set_chain_address(chain_idx); + wots_addr.set_wots_chain_addr(chain_idx); let sk = sig_iter.pop_front().unwrap(); - let chain_pk = chain_hash_128s(ctx, *sk, *len, address); + let chain_pk = chain_hash_128s(ctx, *sk, *len, ref wots_addr); pk.append_span(chain_pk.span()); chain_idx += 1; @@ -86,17 +88,19 @@ pub fn add_checksum_128s(ref message_w: Array) { /// Compute the H^{steps}(input) hash chain given the chain length (start) and return the last /// digest. pub fn chain_hash_128s( - ctx: SpxCtx, input: HashOutput, length: u32, mut address: Address, + ctx: SpxCtx, input: HashOutput, length: u32, ref address: Address, ) -> HashOutput { if length == 15 { return input; } let start: u8 = length.try_into().unwrap(); - address.set_hash_address(start); - let mut output = thash_128s(ctx, address, input.span()); + address.set_wots_hash_addr(start); + + let mut output = thash_128s(ctx, @address, input.span()); + for i in start + 1..15 { // SPX_WOTS_W - 1 - address.set_hash_address(i); - output = thash_128s(ctx, address, output.span()); + address.set_wots_hash_addr(i); + output = thash_128s(ctx, @address, output.span()); } output } @@ -168,21 +172,24 @@ mod tests { #[test] fn test_chain_hash() { let input = [0x01020304, 0x05060708, 0x10203040, 0x50607080]; - let output = chain_hash_128s(Default::default(), input, 5, Default::default()); + let mut address = Default::default(); + let output = chain_hash_128s(Default::default(), input, 5, ref address); assert_eq!(output, [0x8ae6cda7, 0xa098be21, 0x7c81bb4e, 0x860dd304]); } #[test] fn test_chain_hash_2() { let input = [2105475624, 2804661595, 372022634, 664091526]; - let output = chain_hash_128s(Default::default(), input, 15, Default::default()); + let mut address = Default::default(); + let output = chain_hash_128s(Default::default(), input, 15, ref address); assert_eq!(output, [2105475624, 2804661595, 372022634, 664091526]); } #[test] fn test_chain_hash_3() { let input = [1640362213, 3803567762, 3187702095, 90287887]; - let output = chain_hash_128s(Default::default(), input, 9, Default::default()); + let mut address = Default::default(); + let output = chain_hash_128s(Default::default(), input, 9, ref address); assert_eq!(output, [3700563191, 1880524724, 4147099568, 1051379323]); } From 4b67f22963bd23d8722378bec806aaa2a839c1e9 Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Sun, 8 Jun 2025 20:36:42 +0100 Subject: [PATCH 2/8] Add feature flag --- .github/workflows/test.yaml | 12 ++++++++++++ packages/sphincs-plus/Scarb.toml | 4 ++++ packages/sphincs-plus/src/address.cairo | 5 ++++- packages/sphincs-plus/src/hasher.cairo | 3 +++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 8e50a08..ad3f8dd 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -22,3 +22,15 @@ jobs: - name: Run unit tests run: scarb test + + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Scarb + uses: software-mansion/setup-scarb@v1.3.2 + + - name: Build packages + run: scarb build diff --git a/packages/sphincs-plus/Scarb.toml b/packages/sphincs-plus/Scarb.toml index 2706544..2ff17f7 100644 --- a/packages/sphincs-plus/Scarb.toml +++ b/packages/sphincs-plus/Scarb.toml @@ -12,3 +12,7 @@ cairo_execute = "2.11.4" [dev-dependencies] cairo_test = "2.11.4" + +[features] +default = [] +friendly = [] diff --git a/packages/sphincs-plus/src/address.cairo b/packages/sphincs-plus/src/address.cairo index 1697b66..ed03f68 100644 --- a/packages/sphincs-plus/src/address.cairo +++ b/packages/sphincs-plus/src/address.cairo @@ -5,9 +5,12 @@ // Available address implementations. mod dense; mod sparse; +#[cfg(not(feature: "friendly"))] +pub use dense::Address; // Select the chosen Address implementation -pub use dense::Address; +#[cfg(feature: "friendly")] +pub use sparse::Address; use crate::word_array::WordArray; #[derive(Drop)] diff --git a/packages/sphincs-plus/src/hasher.cairo b/packages/sphincs-plus/src/hasher.cairo index c6827fe..b08fcba 100644 --- a/packages/sphincs-plus/src/hasher.cairo +++ b/packages/sphincs-plus/src/hasher.cairo @@ -7,6 +7,9 @@ mod blake2s; mod sha256; // Select the hash function to use. +#[cfg(feature: "friendly")] +pub use blake2s::{HashState, hash_finalize, hash_init, hash_update}; +#[cfg(not(feature: "friendly"))] pub use sha256::{HashState, hash_finalize, hash_init, hash_update}; use crate::address::{Address, AddressTrait, AddressType}; use crate::params_128s::SPX_HASH_LEN; From cccf88fc747e6e861698dc5f458ff0f6ded819b9 Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Sun, 8 Jun 2025 21:02:16 +0100 Subject: [PATCH 3/8] Simplify impl --- .tool-versions | 2 +- packages/sphincs-plus/Scarb.toml | 2 +- packages/sphincs-plus/src/address.cairo | 24 +- packages/sphincs-plus/src/address/dense.cairo | 15 +- .../sphincs-plus/src/address/sparse.cairo | 30 +- packages/sphincs-plus/src/hasher.cairo | 8 +- packages/sphincs-plus/src/sphincs.cairo | 2253 +++-------------- packages/sphincs-plus/src/wots.cairo | 231 +- 8 files changed, 329 insertions(+), 2236 deletions(-) diff --git a/.tool-versions b/.tool-versions index 54a0377..c851524 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -scarb 2.11.4 \ No newline at end of file +scarb nightly-2025-06-07 \ No newline at end of file diff --git a/packages/sphincs-plus/Scarb.toml b/packages/sphincs-plus/Scarb.toml index 2ff17f7..6d6b46b 100644 --- a/packages/sphincs-plus/Scarb.toml +++ b/packages/sphincs-plus/Scarb.toml @@ -14,5 +14,5 @@ cairo_execute = "2.11.4" cairo_test = "2.11.4" [features] -default = [] +default = ["friendly"] friendly = [] diff --git a/packages/sphincs-plus/src/address.cairo b/packages/sphincs-plus/src/address.cairo index ed03f68..30a143d 100644 --- a/packages/sphincs-plus/src/address.cairo +++ b/packages/sphincs-plus/src/address.cairo @@ -5,13 +5,14 @@ // Available address implementations. mod dense; mod sparse; + +// Default address packing according to the sha256-128s parameters. #[cfg(not(feature: "friendly"))] -pub use dense::Address; +pub use dense::{Address, AddressTrait}; -// Select the chosen Address implementation +// Cairo-friendly address packing. #[cfg(feature: "friendly")] -pub use sparse::Address; -use crate::word_array::WordArray; +pub use sparse::{Address, AddressTrait}; #[derive(Drop)] pub enum AddressType { @@ -24,21 +25,6 @@ pub enum AddressType { FORSPRF // 6 } -pub trait AddressTrait { - fn set_hypertree_layer(ref self: T, layer: u8); - fn set_hypertree_addr(ref self: T, tree_address: u64); - fn set_address_type(ref self: T, address_type: AddressType); - fn set_keypair(ref self: T, keypair: u16); - fn set_tree_height(ref self: T, tree_height: u8); - fn set_tree_index(ref self: T, tree_index: u32); - fn set_wots_chain_addr(ref self: T, chain_address: u8); - fn set_wots_hash_addr(ref self: T, hash_address: u8); - fn to_word_array(self: @T) -> WordArray; - - #[cfg(test)] - fn from_components(components: Array) -> T; -} - impl AddressTypeToU32 of Into { fn into(self: AddressType) -> u32 { match self { diff --git a/packages/sphincs-plus/src/address/dense.cairo b/packages/sphincs-plus/src/address/dense.cairo index e2c3de8..3367bae 100644 --- a/packages/sphincs-plus/src/address/dense.cairo +++ b/packages/sphincs-plus/src/address/dense.cairo @@ -6,7 +6,7 @@ //! See https://www.di-mgt.com.au/pqc-09-fors-sig.html for layout details. use crate::word_array::{WordArray, WordArrayTrait}; -use super::{AddressTrait, AddressType}; +use super::AddressType; /// Generic address layout: /// 0 4 8 12 16 20 @@ -25,7 +25,7 @@ use super::{AddressTrait, AddressType}; /// 5. Tree index (4 bytes) /// 6. Wots chain address (1 byte) /// 7. Wots hash address (1 byte) -#[derive(Drop, Clone, Default, Debug)] +#[derive(Drop, Default, Debug, Copy)] pub struct Address { w0: u32, // layer, hypertree address w1: u32, // hypertree address @@ -42,15 +42,8 @@ pub struct Address { w4_cd: u32, } -#[cfg(test)] -pub fn from_components(w0: u32, w1: u32, w2: u32, w3: u32, w4: u32, w5: u32) -> Address { - let (w0_a, w0_bcd) = DivRem::div_rem(w0, 0x1000000); - let (w2_a, w2_b) = DivRem::div_rem(w2 / 0x10000, 0x100); - let (w4_b, w4_cd) = DivRem::div_rem(w4 % 0x1000000, 0x10000); - Address { w0, w1, w2, w3, w4, w5, w0_a, w0_bcd, w2_a, w2_b, w4_b, w4_cd } -} - -pub impl AddressImpl of AddressTrait
{ +#[generate_trait] +pub impl AddressImpl of AddressTrait { #[cfg(test)] fn from_components(mut components: Array) -> Address { let w0 = components.pop_front().unwrap(); diff --git a/packages/sphincs-plus/src/address/sparse.cairo b/packages/sphincs-plus/src/address/sparse.cairo index 76b2a65..79161a1 100644 --- a/packages/sphincs-plus/src/address/sparse.cairo +++ b/packages/sphincs-plus/src/address/sparse.cairo @@ -6,10 +6,10 @@ //! See https://www.di-mgt.com.au/pqc-09-fors-sig.html for layout details. use crate::word_array::{WordArray, WordArrayTrait}; -use super::{AddressTrait, AddressType}; +use super::AddressType; /// Simplified address layout -#[derive(Drop, Default, Debug)] +#[derive(Drop, Default, Debug, Copy)] pub struct Address { layer: u32, hypertree_addr_hi: u32, @@ -22,7 +22,8 @@ pub struct Address { wots_hash_addr: u32, } -pub impl AddressImpl of AddressTrait
{ +#[generate_trait] +pub impl AddressImpl of AddressTrait { #[cfg(test)] fn from_components(mut components: Array) -> Address { let layer = components.pop_front().unwrap(); @@ -84,14 +85,8 @@ pub impl AddressImpl of AddressTrait
{ fn to_word_array(self: @Address) -> WordArray { WordArrayTrait::new( array![ - *self.layer, - *self.hypertree_addr_hi, - *self.hypertree_addr_lo, - *self.address_type, - *self.keypair, - *self.tree_height, - *self.tree_index, - *self.wots_chain_addr, + *self.layer, *self.hypertree_addr_hi, *self.hypertree_addr_lo, *self.address_type, + *self.keypair, *self.tree_height, *self.tree_index, *self.wots_chain_addr, *self.wots_hash_addr, ], 0, @@ -99,16 +94,3 @@ pub impl AddressImpl of AddressTrait
{ ) } } - -impl AddressClone of Clone
{ - fn clone(self: @Address) -> Address { - Address { - layer: *self.layer, - hypertree_addr_hi: *self.hypertree_addr_hi, - hypertree_addr_lo: *self.hypertree_addr_lo, - address_type: *self.address_type, - keypair: *self.keypair, - ..Default::default(), - } - } -} diff --git a/packages/sphincs-plus/src/hasher.cairo b/packages/sphincs-plus/src/hasher.cairo index b08fcba..750b6e5 100644 --- a/packages/sphincs-plus/src/hasher.cairo +++ b/packages/sphincs-plus/src/hasher.cairo @@ -6,11 +6,15 @@ mod blake2s; mod sha256; -// Select the hash function to use. +// Cairo-friendly hash function (custom AIR in Stwo) #[cfg(feature: "friendly")] pub use blake2s::{HashState, hash_finalize, hash_init, hash_update}; + +// Default hash function according to the sha256-128s parameters. #[cfg(not(feature: "friendly"))] pub use sha256::{HashState, hash_finalize, hash_init, hash_update}; + +// Imports. use crate::address::{Address, AddressTrait, AddressType}; use crate::params_128s::SPX_HASH_LEN; use crate::word_array::{WordArray, WordArrayTrait, WordSpan, WordSpanTrait}; @@ -153,7 +157,7 @@ pub fn to_hex(data: Span) -> ByteArray { crate::word_array::hex::words_to_hex(word_span) } -#[cfg(test)] +#[cfg(and(test, not(feature: "friendly")))] mod tests { use crate::word_array::hex::{words_from_hex, words_to_hex}; use super::*; diff --git a/packages/sphincs-plus/src/sphincs.cairo b/packages/sphincs-plus/src/sphincs.cairo index c75e94d..24d30ff 100644 --- a/packages/sphincs-plus/src/sphincs.cairo +++ b/packages/sphincs-plus/src/sphincs.cairo @@ -143,1980 +143,291 @@ mod tests { #[test] fn test_verify_128s() { let mut serialized_sig: Span = array![ - 3641804313, - 3409659048, - 1384169305, - 4015803879, - 3845349652, - 3980556369, - 2345842860, - 1383522053, - 1776444148, - 1913246444, - 629880133, - 807517995, - 2489129527, - 1704974249, - 4233369674, - 1100003695, - 670081949, - 3229823586, - 3156066271, - 2877459785, - 3864387640, - 962594578, - 911814672, - 2016832962, - 1326981663, - 3592066628, - 3818678727, - 2137522501, - 3663275941, - 4067771361, - 3694674432, - 3684846138, - 3702636245, - 385802134, - 609845906, - 984272547, - 1305039906, - 3897311913, - 3980302792, - 249601561, - 1158118636, - 956344437, - 1023701173, - 1314681713, - 1411960911, - 3730304161, - 2683139832, - 3356909473, - 2388706002, - 1141588912, - 3659325720, - 3077858432, - 3527298358, - 2314118033, - 3980145040, - 2123914386, - 3005460189, - 799618523, - 4283005829, - 1963609509, - 448973822, - 3392281748, - 1913893331, - 1146209971, - 2311287984, - 95487622, - 4293653085, - 2185286245, - 811686332, - 3733266479, - 2001227376, - 1564350712, - 3862241750, - 2480308289, - 75193294, - 1827056948, - 2444703908, - 1528035623, - 252591360, - 1907177532, - 3276327886, - 357642290, - 1525373641, - 4070846624, - 1600446942, - 4172547367, - 4117008599, - 1992567557, - 801700287, - 3837426175, - 785551454, - 2568300829, - 4009686221, - 2433702307, - 2227486989, - 3879962447, - 2561294326, - 678237389, - 172530358, - 577304779, - 3643678139, - 2453705289, - 1874419280, - 1623797071, - 1092834586, - 1903739565, - 1410799062, - 4024770158, - 3336271720, - 2140967539, - 4161515794, - 2279338650, - 3922117772, - 480196858, - 3429956549, - 3334061486, - 1012655393, - 3493179932, - 3313296442, - 709768141, - 2211571227, - 979080508, - 2792618267, - 667565804, - 1849209463, - 3482963173, - 445077236, - 414976121, - 4065588426, - 4043683956, - 1459517643, - 2182497638, - 2628200518, - 2917727800, - 1546995338, - 2885697989, - 1916774556, - 2508775278, - 2112605576, - 803353043, - 3461644707, - 2838408325, - 318400135, - 3822977585, - 2213848947, - 1716372608, - 1166639089, - 2946108606, - 616994116, - 1013459948, - 2683935692, - 4031717743, - 2820540258, - 3500500955, - 3109918323, - 2974830952, - 4154212888, - 3354039323, - 4223550271, - 3540853557, - 1791368236, - 1711818464, - 1307829399, - 1883320049, - 2892567381, - 375365615, - 1058086475, - 4153267831, - 4221916521, - 2804585482, - 3601002429, - 2090616214, - 3440304856, - 309895163, - 1339449254, - 2204032088, - 2107709352, - 3518617177, - 2576130346, - 179604206, - 2048043515, - 393494926, - 1492269847, - 4016093241, - 4137437153, - 574991956, - 694061486, - 1823057853, - 576105611, - 512463081, - 685697519, - 1774283082, - 639106710, - 2345765081, - 1886027736, - 3263890599, - 1688408216, - 1657074873, - 687351218, - 1964933744, - 249528114, - 2000070167, - 2159389206, - 1996532773, - 1353612394, - 3982165869, - 2657885677, - 2303272134, - 2818163640, - 4065756780, - 2738950354, - 1956037779, - 2414425867, - 1973544800, - 320170604, - 925231311, - 2455496728, - 2883443195, - 1490713387, - 3017823688, - 4241218393, - 2219148985, - 628819248, - 2939969314, - 177752055, - 3578065884, - 3905559371, - 3368581155, - 241040034, - 911239107, - 3435679378, - 1407384387, - 1396365726, - 3761063842, - 11888979, - 77084202, - 2138333885, - 236378764, - 2134882302, - 1573999454, - 1627819515, - 3230097309, - 3831670565, - 2842829451, - 4274748579, - 2240984806, - 952818735, - 388331066, - 2632860657, - 3349117205, - 632606381, - 3344410471, - 675067528, - 2404347262, - 1342305026, - 2706079803, - 475921287, - 1677629046, - 297106715, - 4240261903, - 3540998797, - 2364808562, - 3756352841, - 1918883116, - 2524764992, - 3020870704, - 680783868, - 1458032803, - 3355696017, - 4108651072, - 619123037, - 3636910850, - 38029166, - 889619814, - 2779459159, - 547835927, - 3287886895, - 410955316, - 1583479435, - 921168593, - 274504600, - 1269870552, - 630286762, - 1614185261, - 607438949, - 685540797, - 3031239454, - 375011737, - 2988756236, - 3398598350, - 1321195186, - 3196494495, - 2851400759, - 2336728473, - 190438675, - 261435140, - 1542519290, - 2155683804, - 1118260314, - 3915141211, - 2706284434, - 1463761718, - 598597022, - 718959274, - 1040120845, - 1653688289, - 1646375500, - 785395071, - 2582855538, - 2950135274, - 3120683159, - 2438705142, - 2562837108, - 172083909, - 3533122256, - 642625578, - 1916636818, - 3937105575, - 978091614, - 906286264, - 3590166484, - 686068513, - 1062386605, - 3506372956, - 690358374, - 2836659061, - 1544004463, - 948095108, - 2121516496, - 3145783543, - 3317829736, - 1747789312, - 2531814391, - 3890442684, - 2818085288, - 2464153947, - 1481243090, - 276217925, - 3528495726, - 1905935399, - 2226427326, - 2086581637, - 4057202032, - 359616860, - 3056962263, - 2860291775, - 842289383, - 2383199900, - 970659426, - 2493195055, - 2856530586, - 1857349796, - 1752828277, - 2544869978, - 347670364, - 1697735707, - 701641463, - 1495395009, - 708234435, - 71228858, - 6725319, - 3729042962, - 1322267034, - 3562179679, - 390392117, - 2718661891, - 4119722260, - 3016165981, - 173636303, - 247793828, - 2210075214, - 2453528372, - 878495536, - 4138879103, - 3198938655, - 1153023580, - 3656466086, - 1921278912, - 4259770210, - 4025887727, - 716454805, - 2675991660, - 764352060, - 2061427150, - 644202169, - 410489069, - 1593496319, - 1573762196, - 3949934278, - 3833307389, - 2174149463, - 559379456, - 1359418491, - 997482747, - 761315516, - 1656437760, - 2801700048, - 3748972674, - 2259204497, - 1362944958, - 2946615863, - 673289952, - 940765530, - 366736455, - 1320319724, - 1362593883, - 3457327010, - 1134213393, - 427373482, - 3599931665, - 1588374585, - 1646426782, - 509825313, - 2001698005, - 1176187577, - 2634244039, - 1070336223, - 3415726364, - 215320212, - 1449139043, - 742200464, - 4209002780, - 2288931600, - 4229843766, - 193606371, - 3561138658, - 4133177363, - 2413226392, - 2496965490, - 3644482506, - 340536440, - 2090666858, - 1169098255, - 2180302090, - 1332098645, - 3519593925, - 2034913842, - 3228903288, - 3590605244, - 2043663430, - 3898913249, - 3419698288, - 1687179296, - 426138261, - 1800833856, - 852965144, - 1231468533, - 1422804543, - 371324314, - 3637780806, - 1165909850, - 1006939933, - 1795186501, - 1129865295, - 3578796776, - 1944628477, - 2325429195, - 864154197, - 1894479132, - 2957055800, - 3446306487, - 1613516288, - 1401983377, - 3217840062, - 455266767, - 3444044805, - 3408708917, - 67660920, - 1130827181, - 1226112436, - 2651987560, - 2145498380, - 843224815, - 3345197520, - 3247048414, - 623892268, - 2931986917, - 239431919, - 1696049201, - 3986120789, - 26575503, - 86884437, - 4056010433, - 1649158999, - 2384122627, - 260528266, - 3642906969, - 299908390, - 2053891086, - 3661512858, - 1351916795, - 2401047532, - 4161527555, - 3281787047, - 697091227, - 2783235332, - 3810349867, - 3643204404, - 746367499, - 3391821244, - 2910660296, - 3113812611, - 2108281660, - 683621710, - 1540660850, - 914865064, - 3788165535, - 714752705, - 1131723309, - 1256015046, - 523998286, - 3188590484, - 2727575505, - 4140645458, - 1289411501, - 3165995413, - 3352995463, - 3791561200, - 2673333513, - 4110565571, - 305608709, - 2009689483, - 1860741830, - 1345337841, - 2755252410, - 2950721341, - 659291128, - 1227069782, - 1415504028, - 1569236383, - 31519830, - 2177707915, - 562429604, - 2556441832, - 3422139644, - 915492748, - 3074460773, - 1135416931, - 649823245, - 645334249, - 2200862131, - 1521286820, - 2908520411, - 3101024341, - 625340248, - 1363709939, - 3604107235, - 936078234, - 4012943112, - 3989300683, - 1639985469, - 3243402231, - 752354804, - 1489406340, - 1457484819, - 2059496004, - 3672752421, - 2323695461, - 651127002, - 628206064, - 954208968, - 1528822556, - 1147274155, - 2206289820, - 3236604581, - 894257554, - 1006545288, - 2610663838, - 500086413, - 1861737234, - 1337328785, - 1846887892, - 3157530625, - 978084610, - 93655214, - 4272965685, - 3324875949, - 3280061343, - 3738893064, - 2946628304, - 856234701, - 3086444665, - 694808254, - 1813880914, - 4127555462, - 2936029435, - 2523356556, - 2438706698, - 1835377519, - 3004798523, - 3255049351, - 2645300243, - 77871166, - 3319880385, - 4067278601, - 3098242181, - 3325101113, - 2772478697, - 801534108, - 1242913681, - 1974780461, - 3389506397, - 1336588894, - 393129198, - 2783030854, - 2203427106, - 1109383207, - 1719283460, - 3041243849, - 261666695, - 1025535106, - 923453286, - 827717779, - 2807039265, - 1933118943, - 3274244551, - 1889699541, - 1265328665, - 1943061121, - 1042270043, - 4002841458, - 372231042, - 325095059, - 919156966, - 1559688844, - 297972731, - 1058124675, - 3463490561, - 4186279382, - 2585599754, - 4031687143, - 255362872, - 2718851830, - 2441505029, - 3559629598, - 161284861, - 1992175784, - 3915485134, - 84323157, - 141131997, - 2756061329, - 179913101, - 3330332543, - 3136211599, - 2603901635, - 4227256437, - 2922178905, - 616595963, - 3175500824, - 1655253586, - 327289320, - 3770920662, - 848693221, - 3503841802, - 3931259556, - 1022855830, - 2859936314, - 513909550, - 3999727525, - 2526957429, - 2821984537, - 2597122982, - 1412326700, - 3832231820, - 3168678466, - 2645115637, - 321303366, - 2449201471, - 2555994028, - 3067904292, - 4272299652, - 3172742871, - 2373897040, - 3262703632, - 2201529522, - 4242934543, - 2919992911, - 1436165986, - 2033017928, - 3066712322, - 3681817762, - 3970838867, - 2855719673, - 506845064, - 3660680647, - 1903888229, - 483654580, - 3933223724, - 3283979865, - 407468681, - 1168530006, - 2990704403, - 815024928, - 3889928435, - 2491617549, - 1991884684, - 3507821195, - 1519742370, - 3811922359, - 621838161, - 1818574590, - 1216501288, - 3838181218, - 1758746829, - 3152172586, - 3654785573, - 4187946456, - 962740404, - 1598170463, - 1844781445, - 1083364221, - 914277180, - 3307998213, - 280531881, - 3674295517, - 983896622, - 3587758496, - 3506890319, - 612201946, - 1594301102, - 3557203990, - 3452646665, - 746355999, - 3219848916, - 579876051, - 2334310192, - 1891407089, - 675744779, - 1079614653, - 1305614539, - 22268105, - 350406580, - 2228346597, - 4142391977, - 3304705805, - 2643224540, - 2346692777, - 3811306839, - 2055912668, - 163083647, - 2333826953, - 2151057460, - 3941937039, - 1085635170, - 1112366764, - 735116963, - 2277711192, - 3718251113, - 3234345339, - 3079451072, - 1597196335, - 535008840, - 3134500306, - 2002330654, - 1946854270, - 2150715541, - 1207738170, - 2635825461, - 3280844938, - 3595479391, - 4046757619, - 3676083000, - 2521337294, - 4211202760, - 1127070492, - 463581130, - 1572521594, - 1362987995, - 158041764, - 2152374263, - 560798666, - 2464343623, - 647027940, - 1153071868, - 3545021547, - 903696024, - 1085151946, - 3076244929, - 4071821109, - 3577654894, - 347719294, - 1985137777, - 506009938, - 3043974844, - 1224943034, - 2441674287, - 943278257, - 1345453507, - 1693293667, - 2900784417, - 1631023524, - 1765603555, - 1126325548, - 2921853563, - 2146353962, - 998613971, - 514840483, - 1023293489, - 3615741723, - 2369262290, - 656145243, - 1354305259, - 2947584320, - 4176666913, - 2725299359, - 3261612155, - 255828942, - 3388332780, - 3297000689, - 1523045439, - 3365583669, - 486896888, - 1170116441, - 3755093041, - 2612246577, - 4165702021, - 634956699, - 3768307260, - 1328309876, - 948878956, - 3444220003, - 362000903, - 2864691130, - 507529696, - 2930154584, - 3635605629, - 2886604763, - 1701207604, - 650477935, - 1278563275, - 1152046466, - 2842388098, - 3155750550, - 1913296439, - 3796154204, - 1373623833, - 1829190240, - 2402164973, - 3534925063, - 1350190204, - 3766380825, - 2884139564, - 4000978894, - 4250218774, - 1694124076, - 3647405317, - 3450510830, - 297575619, - 3239433082, - 2321033644, - 1593523758, - 986488941, - 927914435, - 1041323457, - 3052530576, - 4122441236, - 3679849671, - 1129141796, - 3385482782, - 3271988188, - 1637458982, - 3365075758, - 3327750380, - 915073093, - 3973890572, - 2936228140, - 3281245874, - 3370332651, - 801307974, - 3367310492, - 4025581329, - 3744265314, - 3141527609, - 783285243, - 1024284631, - 1662557967, - 4288387661, - 3850518314, - 3999781803, - 3479141110, - 1226667474, - 2237093609, - 1871582151, - 4030420346, - 593353899, - 2848318175, - 4135113486, - 3367015917, - 126745884, - 3109648786, - 3558908978, - 3548495984, - 3114288752, - 3697000294, - 2490559532, - 3888775359, - 358178714, - 1951854291, - 2275007118, - 4151980360, - 298857474, - 3736529133, - 2961456632, - 196996783, - 2454543290, - 1339045573, - 2697951962, - 2819473132, - 1306910810, - 1735981146, - 2695155186, - 4153090923, - 3374802720, - 2397801981, - 410696114, - 589256661, - 1489109647, - 975636822, - 3988780217, - 1904014052, - 2922748256, - 708153852, - 3861011602, - 1222762022, - 3096481891, - 3901201549, - 1176473345, - 2150797357, - 1952018225, - 104031537, - 1424303343, - 1792851996, - 1810265303, - 2810033694, - 1921090978, - 2889572543, - 2787907754, - 1596110156, - 260692140, - 3729584744, - 716675854, - 1179319491, - 1796748177, - 71608814, - 1742751168, - 2736750551, - 1914149388, - 830787397, - 1386733720, - 3073223633, - 1151062847, - 1892436425, - 2187447358, - 1977238084, - 363476021, - 3429583327, - 402781814, - 781128806, - 4244331924, - 2494700575, - 3735841530, - 3001940434, - 1301696657, - 152848131, - 1164018513, - 2733754197, - 3589134520, - 1972719071, - 3795946134, - 3112071646, - 1810134638, - 955771191, - 849034716, - 3543622175, - 2412624989, - 1849274312, - 2880121793, - 1482761278, - 2303516731, - 687795802, - 1932236885, - 277889281, - 2644543154, - 3349742966, - 498944828, - 3159123266, - 2094448658, - 949728498, - 2624370130, - 2862797877, - 3455600769, - 1752853916, - 3196084250, - 251319934, - 3798443074, - 447885757, - 3109173711, - 3333486255, - 4136551940, - 1851600054, - 1273576027, - 3889307657, - 1009210572, - 2904428566, - 4066366542, - 81331318, - 3077464197, - 2504370765, - 1914551841, - 3595673347, - 2279275163, - 2895614653, - 4004322562, - 2781486796, - 557234246, - 3240119385, - 1474375840, - 1748689310, - 3190126248, - 832119346, - 1656610142, - 2089515031, - 3173461525, - 3482745970, - 3396179284, - 2752402192, - 2967125248, - 1773637785, - 529966979, - 276760102, - 2667014268, - 2129514719, - 2947217782, - 4065778689, - 112424943, - 3049102676, - 455115487, - 1843393324, - 896703959, - 3863808184, - 2285702025, - 2527940087, - 1194581980, - 330894106, - 1235505341, - 1239511919, - 513391968, - 1574835140, - 2637052830, - 1489734447, - 3462608188, - 3853430832, - 44976308, - 1465077781, - 2984715170, - 1493217435, - 3842116629, - 4282698888, - 3942540872, - 3310013608, - 3043245350, - 1118287730, - 3535672347, - 1225429595, - 3996492203, - 521109925, - 2780037099, - 1788178032, - 3363008600, - 4159442270, - 1279718880, - 3336828392, - 3281491867, - 3678359654, - 2590189543, - 1755642657, - 3797171953, - 3940770955, - 2424081100, - 2985789408, - 987668658, - 895616615, - 2619071987, - 952588159, - 530271896, - 2255848659, - 996616018, - 1480991213, - 2375501561, - 1135199032, - 1010174044, - 3663512884, - 419279564, - 2134518764, - 81322211, - 2909309622, - 334695784, - 2390255124, - 484096560, - 1429331258, - 1695288986, - 933327260, - 1144889677, - 2630062765, - 4136242651, - 1154319202, - 4178377937, - 3871010999, - 978633896, - 1124790846, - 3872961237, - 2359087957, - 2713332437, - 2067169477, - 3218791441, - 2417082480, - 2950387228, - 711207861, - 3905938888, - 1072297456, - 780058137, - 2225327061, - 66019917, - 2101309172, - 781732246, - 2915984650, - 907717265, - 349157973, - 2571074611, - 1836556611, - 242912724, - 3435716719, - 3021264709, - 608905744, - 231754520, - 3628024202, - 3540870844, - 2698200065, - 3370666951, - 679176354, - 873060091, - 1824713668, - 2354137422, - 3956522608, - 3912379829, - 2941940140, - 1659750710, - 3554891308, - 2203113685, - 2970109543, - 4016203021, - 2190622424, - 401362631, - 2136413586, - 506344911, - 3328130215, - 2873829637, - 3883674672, - 1735707197, - 2851213471, - 3636007066, - 3576142781, - 920635286, - 3414277027, - 755640444, - 224699414, - 477577470, - 3046142152, - 1393292158, - 1434828494, - 1060405281, - 1996479056, - 2678833306, - 2252179338, - 860115768, - 1116533040, - 3018630432, - 112735461, - 2035706152, - 763718853, - 2823484451, - 1754287104, - 2664502817, - 3585354939, - 732548627, - 2175348082, - 233002529, - 2019361456, - 3523232597, - 2101058708, - 2130251156, - 3667165550, - 1447145780, - 1368365682, - 1409672843, - 2662508723, - 3256925752, - 2808642181, - 85804983, - 3369281785, - 1883595751, - 1123696267, - 616532342, - 1678240924, - 1393929910, - 2830042662, - 3876251704, - 1968769983, - 1639145269, - 49550780, - 374866824, - 110504714, - 3303116796, - 2411786404, - 3099711676, - 1157367152, - 692800170, - 681888974, - 1919966704, - 672504458, - 2819918429, - 1169544583, - 936968114, - 2520693949, - 1435498099, - 1156122806, - 2803887655, - 128491806, - 1027089845, - 2700739409, - 288869674, - 2093162014, - 1199366336, - 1452631673, - 589696736, - 910548969, - 1944921731, - 1078368879, - 4155043530, - 2493773362, - 2118362864, - 3939034270, - 3366844078, - 3745811564, - 952783004, - 1650335956, - 3883669193, - 770913022, - 3405982998, - 2619848605, - 735716470, - 1907987463, - 3237980455, - 1662385035, - 3017028838, - 3524707041, - 2392747612, - 3722871952, - 3263101367, - 620748022, - 2443637548, - 3324016375, - 684174418, - 3861376463, - 1979953065, - 519879078, - 1047123184, - 2446164799, - 2377242800, - 2933899494, - 41432330, - 94026108, - 3267986354, - 4168280259, - 2705573896, - 3360605438, - 3365914548, - 3406807268, - 1995869767, - 3669573002, - 1845408832, - 863506975, - 3404003784, - 2126651504, - 14799952, - 2994833187, - 4176848320, - 452676058, - 1664278670, - 893912181, - 3784216926, - 2669847142, - 1014136786, - 3801538065, - 306096503, - 1668645734, - 4127485751, - 305365825, - 3104772045, - 1005162901, - 3854879829, - 2646981055, - 4075778792, - 637633254, - 2098343553, - 4068135114, - 3385210946, - 140099086, - 1225070629, - 3389371958, - 1850430746, - 73349102, - 490078699, - 1347332780, - 875789524, - 209085107, - 1507865019, - 1210427799, - 515723706, - 1868027722, - 2058975055, - 4270443277, - 1366025695, - 105646624, - 1509788154, - 890549141, - 3908953447, - 807341053, - 224539810, - 659547130, - 2780704405, - 1861784153, - 3419852638, - 2071538606, - 131798003, - 2420415589, - 3854683022, - 4000833859, - 2684812347, - 2088735124, - 2700426241, - 2640680156, - 34053997, - 3906621832, - 1423946216, - 516493097, - 2897244512, - 3703450183, - 3235085733, - 2708698459, - 3741097740, - 1551680475, - 376177994, - 351898921, - 552249933, - 922521851, - 91876389, - 1044244206, - 1115857743, - 3521017455, - 587340439, - 2190908905, - 1712180168, - 323825696, - 3387372619, - 858685730, - 3729385118, - 3805205604, - 2378887338, - 3718437268, - 477040385, - 3124665320, - 1808730625, - 709692573, - 1936795956, - 562417108, - 1963827974, - 3538447015, - 1782736438, - 2457129116, - 3990965080, - 1871133930, - 2972028029, - 3867007479, - 597477621, - 4254333800, - 191676744, - 2731291088, - 1756855263, - 1507146434, - 3101630736, - 2053580818, - 3087659003, - 412528102, - 3666146766, - 1864436374, - 589191486, - 3034015201, - 2146647765, - 2772471410, - 819324439, - 1925031770, - 4052060806, - 3928995908, - 2706898868, - 595467632, - 240328025, - 334044202, - 3728473436, - 624775586, - 106994446, - 1102919260, - 42923722, - 585566309, - 3050414830, - 1510865011, - 1098762897, - 2583442585, - 614228805, - 2402539396, - 770290105, - 308031879, - 425687430, - 1218449747, - 2716558921, - 1929243434, - 1257229287, - 2176542367, - 706728595, - 2508641353, - 1027518972, - 3961844074, - 2501009749, - 172703717, - 2790230787, - 428147405, - 3484324062, - 810177957, - 4162401982, - 2267452562, - 752562144, - 1024230228, - 2679993640, - 3119356373, - 1876755195, - 4044474080, - 3571275564, - 1938373684, - 2893917153, - 1490860820, - 973674173, - 858741651, - 456556454, - 1434026249, - 814434097, - 2033138969, - 4101399879, - 1949227476, - 2584791597, - 1714626029, - 3337395475, - 26118094, - 1868010440, - 1981814574, - 2218139522, - 2782093872, - 3603407779, - 631332877, - 1807142192, - 878520063, - 356991133, - 1672471476, - 2194833618, - 3935901757, - 2991388597, - 1628214501, - 2032168122, - 1538003368, - 314370106, - 1753143679, - 915672542, - 3509957993, - 2105542408, - 1414588250, - 3985143727, - 1495656623, - 322802058, - 3824061544, - 1469606935, - 1632468337, - 283337945, - 3439221703, - 3298553199, - 2289504381, - 2045978609, - 1429608058, - 2785464005, - 2773134905, - 136757740, - 3445930290, - 2463142191, - 2629280359, - 311480240, - 4204965565, - 410971468, - 1113488820, - 3222795507, - 2025087398, - 1665466436, - 3943908042, - 2765449529, - 1257311034, - 3531720973, - 20854566, - 4021342790, - 3785433655, - 2630218088, - 3644807264, - 3901371304, - 3640948520, - 3863350694, - 849148797, - 1326141603, - 68161277, - 1841270523, - 3554223789, - 3438932258, - 3877847149, - 3017846090, - 3147387441, - 3776462537, - 3347070451, - 2720210508, - 4097699213, - 4174324637, - 1587629731, - 3444565438, - 4187384763, - 3418638828, - 1707503688, - 3341712856, - 3105001597, - 1780597032, - 1387803205, - 4119973268, - 390641452, - 767760632, - 2358376934, - 3024095833, - 2271575256, - 88914562, - 1265060538, - 3624171743, - 3693253351, - 2197037019, - 1711449662, - 3127263788, - 2011052893, - 2342704676, - 2923024911, - 2056538871, - 3732228102, - 1787620293, - 3986983402, - 3508033674, - 787856342, - 3876073650, - 1021493958, - 661311052, - 1284817664, - 3510068761, - 2160462585, - 531089334, - 2341862479, - 2123225605, - 2975069226, - 1454648120, - 2709538076, - 186380217, - 51898702, - 701714190, - 3506612549, - 3320428182, - 2859339848, - 3533713154, - 3089919192, - 1882195296, - 1485897784, - 2486962360, - 758415433, - 236079331, - 1475515301, - 4008271342, - 3979313520, - 1531588689, - 3883571822, - 2800232407, - 4037999571, - 3652352852, - 2280544750, - 583718393, - 19789151, - 1332193092, - 772436346, - 2742865239, - 3119469865, - 2267207740, - 2140203778, - 2177551680, - 4020473607, - 261823465, - 1931847234, - 1585658818, - 2547861539, - 4015864930, - 1958364072, - 1428836105, - 1679472026, - 585029714, - 4006545224, - 3411279427, - 3792127768, - 3175098739, - 3969847819, - 1483422140, - 765230573, - 3736767369, - 1706282872, - 329305623, - 1040695644, - 1684881032, - 1272407531, - 3420521971, - 3522034443, - 2810848885, - 1835779799, - 2719122496, - 4237209588, - 1286977410, - 1787800433, - 4223355912, - 1284776076, - 556616816, - 4282812965, - 2160424700, - 1382593239, - 2516045926, - 1797407435, - 500920808, - 419547784, - 2079330089, - 3497103530, - 3481439636, - 3862364895, - 3265084289, - 2879758787, - 3683708282, - 2112436418, - 748366440, - 1662479434, - 963293795, - 1836902165, - 953512895, - 156893596, - 3742477156, - 1534951954, - 9867783, - 1071123538, - 826169636, - 1473699940, - 1398802769, - 3489413400, - 3279858489, - 3207769749, - 1844726812, - 3640642524, - 2750335002, - 764406419, - 1596487257, - 1499341750, - 2073530828, - 1551767693, - 2947058908, - 1183294128, - 2827044301, - 4264376236, - 3544323998, - 4287124850, - 846655561, - 1827068722, - 3819523089, - 2772662699, - 352633126, - 1158231489, - 2562677750, - 3345612115, - 1147418734, - 1487887911, - 3309945982, - 3849891818, - 3652696420, - 394907872, - 3103434701, - 918406158, - 2768564891, - 3147089136, - 2907819317, - 2888373797, - 2787755534, - 3859514895, - 4232431754, - 4042962333, - 1281492509, - 4002419688, - 2820985804, - 1704023742, - 1644797208, - 1173714635, - 2408376672, - 2375732576, - 1415179609, - 2602999317, - 593531553, - 2176498712, - 2695591207, - 2883179730, - 2694207120, - 1125555211, - 1563183910, - 4258821389, - 3403046251, - 4017944083, - 2698730212, - 3338185430, - 3045691178, - 575737880, - 685139618, - 1589153891, - 412178860, - 1162633267, - 1944345456, - 1967006725, - 1024255981, - 3786327406, - 542804109, - 4157467010, - 1727500843, - 3573604690, - 2111353503, - 368315225, - 2520704128, - 1796561125, - 1626435200, - 2254886653, - 128840242, - 808001143, - 1500739954, - 2063642899, - 2587711609, - 107802700, - 4229794616, - 2670693803, - 207878725, - 2495604032, - 3109053527, - 546978918, - 1043648137, - 1631274412, - 365839054, - 2919485597, - 3150710342, - 1028492706, - 2619056173, - 3962815864, - 2475158716, - 259533563, - 1457916063, - 3603646061, - 3372366726, - 2731736922, - 1515197060, - 1109717083, - 4066793286, - 2853741238, - 618499060, - 3815610005, - 2645879110, - 591389873, - 4155648255, - 1218458888, - 2043318599, - 4245099975, - 2766607503, - 3739099184, - 2225793897, - 1669959178, - 1638798981, - 1052699271, - 875834115, - 1387274512, - 497897420, - 378912777, - 1229567296, - 2979929820, - 1234317587, - 2242823157, - 616076844, - 1198176565, - 1697526339, - 2952269296, - 259510251, - 2292463341, - 1110763338, - 2834419408, - 2243897317, - 1357218200, - 175777809, - 1599835643, - 2759933309, - 2740298552, - 1197317042, - 391179902, - 1726063293, - 1567600416, - 562374088, - 2697654974, - 743885610, - 3911955293, - 595978879, - 2492978036, - 395457576, - 3679105244, - 242145418, - 3206358366, - 2022718346, - 2508006231, - 2700101394, - 2199368386, - 1551314058, - 3883557458, - 31200113, - 362076179, - 3942542681, - 2170957456, - 1199261872, - 1711076146, - 1350016364, - 1091747881, - 1136504139, - 926715789, - 3397378635, - 669618995, - 807042417, - 3035670333, - 3354691559, - 2149754843, - 3267393448, - 4110214699, - 938638546, - 2805826602, - 2110240297, - 1257861712, - 3673175951, - 968345689, - 2938600642, - 230127878, - 2501408740, - 3127939871, - 3854966148, - 608822848, - 3708451507, - 2424468861, - 4143788443, - 3575886569, - 1861677604, - 149446520, - 3976299715, - 2890510284, - 1519510981, - 1432498595, - 104357924, - 3965381525, - 1017803683, - 2903665224, - 2408631199, - 10279575, - 903811517, - 2659504123, - 275520645, - 555960480, - 2962976657, - 3833820553, - 3810980845, - 3521925688, - 3963447715, - 4000932047, - 2355064254, - 1043006088, - 4081568384, - 2669175964, - 777710945, - 3736663677, - 2929722329, - 932990103, - 3516119447, - 470504753, - 3693725292, - 1240779264, - 1628339353, - 3979066608, - 881829213, - 4110505327, - 2808632111, - 960805185, - 1304389985, - 2591031922, - 1586405142, - 1704897803, - 325652170, - 2697134023, - 834249473, - 1541424001, - 2934973207, - 2581256919, - 3936746829, - 1723826973, - 3152187997, - 3596020452, - 120414603, - 1848962662, - 1124638409, - 1008154130, - 1002411255, - 2287996684, - 140510448, - 1550243287, - 334959613, - 4179574024, - 3449843246, - 485728905, - 3866347246, - 1653540960, - 911548578, - 1902101785, - 324446669, - 2326552094, - 3473905612, - 1850204311, - 3210536218, - 422961006, - 2570390056, - 1505254050, - 2797016905, - 537654640, - 3622538924, - 192474565, - 1663354207, - 1705814826, - 3326083849, - 3982462806, - 1122161436, - 1325027385, - 1866891611, - 2284363446, + 3641804313, 3409659048, 1384169305, 4015803879, 3845349652, 3980556369, 2345842860, + 1383522053, 1776444148, 1913246444, 629880133, 807517995, 2489129527, 1704974249, + 4233369674, 1100003695, 670081949, 3229823586, 3156066271, 2877459785, 3864387640, + 962594578, 911814672, 2016832962, 1326981663, 3592066628, 3818678727, 2137522501, + 3663275941, 4067771361, 3694674432, 3684846138, 3702636245, 385802134, 609845906, + 984272547, 1305039906, 3897311913, 3980302792, 249601561, 1158118636, 956344437, + 1023701173, 1314681713, 1411960911, 3730304161, 2683139832, 3356909473, 2388706002, + 1141588912, 3659325720, 3077858432, 3527298358, 2314118033, 3980145040, 2123914386, + 3005460189, 799618523, 4283005829, 1963609509, 448973822, 3392281748, 1913893331, + 1146209971, 2311287984, 95487622, 4293653085, 2185286245, 811686332, 3733266479, + 2001227376, 1564350712, 3862241750, 2480308289, 75193294, 1827056948, 2444703908, + 1528035623, 252591360, 1907177532, 3276327886, 357642290, 1525373641, 4070846624, + 1600446942, 4172547367, 4117008599, 1992567557, 801700287, 3837426175, 785551454, + 2568300829, 4009686221, 2433702307, 2227486989, 3879962447, 2561294326, 678237389, + 172530358, 577304779, 3643678139, 2453705289, 1874419280, 1623797071, 1092834586, + 1903739565, 1410799062, 4024770158, 3336271720, 2140967539, 4161515794, 2279338650, + 3922117772, 480196858, 3429956549, 3334061486, 1012655393, 3493179932, 3313296442, + 709768141, 2211571227, 979080508, 2792618267, 667565804, 1849209463, 3482963173, + 445077236, 414976121, 4065588426, 4043683956, 1459517643, 2182497638, 2628200518, + 2917727800, 1546995338, 2885697989, 1916774556, 2508775278, 2112605576, 803353043, + 3461644707, 2838408325, 318400135, 3822977585, 2213848947, 1716372608, 1166639089, + 2946108606, 616994116, 1013459948, 2683935692, 4031717743, 2820540258, 3500500955, + 3109918323, 2974830952, 4154212888, 3354039323, 4223550271, 3540853557, 1791368236, + 1711818464, 1307829399, 1883320049, 2892567381, 375365615, 1058086475, 4153267831, + 4221916521, 2804585482, 3601002429, 2090616214, 3440304856, 309895163, 1339449254, + 2204032088, 2107709352, 3518617177, 2576130346, 179604206, 2048043515, 393494926, + 1492269847, 4016093241, 4137437153, 574991956, 694061486, 1823057853, 576105611, + 512463081, 685697519, 1774283082, 639106710, 2345765081, 1886027736, 3263890599, + 1688408216, 1657074873, 687351218, 1964933744, 249528114, 2000070167, 2159389206, + 1996532773, 1353612394, 3982165869, 2657885677, 2303272134, 2818163640, 4065756780, + 2738950354, 1956037779, 2414425867, 1973544800, 320170604, 925231311, 2455496728, + 2883443195, 1490713387, 3017823688, 4241218393, 2219148985, 628819248, 2939969314, + 177752055, 3578065884, 3905559371, 3368581155, 241040034, 911239107, 3435679378, + 1407384387, 1396365726, 3761063842, 11888979, 77084202, 2138333885, 236378764, + 2134882302, 1573999454, 1627819515, 3230097309, 3831670565, 2842829451, 4274748579, + 2240984806, 952818735, 388331066, 2632860657, 3349117205, 632606381, 3344410471, + 675067528, 2404347262, 1342305026, 2706079803, 475921287, 1677629046, 297106715, + 4240261903, 3540998797, 2364808562, 3756352841, 1918883116, 2524764992, 3020870704, + 680783868, 1458032803, 3355696017, 4108651072, 619123037, 3636910850, 38029166, + 889619814, 2779459159, 547835927, 3287886895, 410955316, 1583479435, 921168593, + 274504600, 1269870552, 630286762, 1614185261, 607438949, 685540797, 3031239454, + 375011737, 2988756236, 3398598350, 1321195186, 3196494495, 2851400759, 2336728473, + 190438675, 261435140, 1542519290, 2155683804, 1118260314, 3915141211, 2706284434, + 1463761718, 598597022, 718959274, 1040120845, 1653688289, 1646375500, 785395071, + 2582855538, 2950135274, 3120683159, 2438705142, 2562837108, 172083909, 3533122256, + 642625578, 1916636818, 3937105575, 978091614, 906286264, 3590166484, 686068513, + 1062386605, 3506372956, 690358374, 2836659061, 1544004463, 948095108, 2121516496, + 3145783543, 3317829736, 1747789312, 2531814391, 3890442684, 2818085288, 2464153947, + 1481243090, 276217925, 3528495726, 1905935399, 2226427326, 2086581637, 4057202032, + 359616860, 3056962263, 2860291775, 842289383, 2383199900, 970659426, 2493195055, + 2856530586, 1857349796, 1752828277, 2544869978, 347670364, 1697735707, 701641463, + 1495395009, 708234435, 71228858, 6725319, 3729042962, 1322267034, 3562179679, 390392117, + 2718661891, 4119722260, 3016165981, 173636303, 247793828, 2210075214, 2453528372, + 878495536, 4138879103, 3198938655, 1153023580, 3656466086, 1921278912, 4259770210, + 4025887727, 716454805, 2675991660, 764352060, 2061427150, 644202169, 410489069, + 1593496319, 1573762196, 3949934278, 3833307389, 2174149463, 559379456, 1359418491, + 997482747, 761315516, 1656437760, 2801700048, 3748972674, 2259204497, 1362944958, + 2946615863, 673289952, 940765530, 366736455, 1320319724, 1362593883, 3457327010, + 1134213393, 427373482, 3599931665, 1588374585, 1646426782, 509825313, 2001698005, + 1176187577, 2634244039, 1070336223, 3415726364, 215320212, 1449139043, 742200464, + 4209002780, 2288931600, 4229843766, 193606371, 3561138658, 4133177363, 2413226392, + 2496965490, 3644482506, 340536440, 2090666858, 1169098255, 2180302090, 1332098645, + 3519593925, 2034913842, 3228903288, 3590605244, 2043663430, 3898913249, 3419698288, + 1687179296, 426138261, 1800833856, 852965144, 1231468533, 1422804543, 371324314, + 3637780806, 1165909850, 1006939933, 1795186501, 1129865295, 3578796776, 1944628477, + 2325429195, 864154197, 1894479132, 2957055800, 3446306487, 1613516288, 1401983377, + 3217840062, 455266767, 3444044805, 3408708917, 67660920, 1130827181, 1226112436, + 2651987560, 2145498380, 843224815, 3345197520, 3247048414, 623892268, 2931986917, + 239431919, 1696049201, 3986120789, 26575503, 86884437, 4056010433, 1649158999, + 2384122627, 260528266, 3642906969, 299908390, 2053891086, 3661512858, 1351916795, + 2401047532, 4161527555, 3281787047, 697091227, 2783235332, 3810349867, 3643204404, + 746367499, 3391821244, 2910660296, 3113812611, 2108281660, 683621710, 1540660850, + 914865064, 3788165535, 714752705, 1131723309, 1256015046, 523998286, 3188590484, + 2727575505, 4140645458, 1289411501, 3165995413, 3352995463, 3791561200, 2673333513, + 4110565571, 305608709, 2009689483, 1860741830, 1345337841, 2755252410, 2950721341, + 659291128, 1227069782, 1415504028, 1569236383, 31519830, 2177707915, 562429604, + 2556441832, 3422139644, 915492748, 3074460773, 1135416931, 649823245, 645334249, + 2200862131, 1521286820, 2908520411, 3101024341, 625340248, 1363709939, 3604107235, + 936078234, 4012943112, 3989300683, 1639985469, 3243402231, 752354804, 1489406340, + 1457484819, 2059496004, 3672752421, 2323695461, 651127002, 628206064, 954208968, + 1528822556, 1147274155, 2206289820, 3236604581, 894257554, 1006545288, 2610663838, + 500086413, 1861737234, 1337328785, 1846887892, 3157530625, 978084610, 93655214, + 4272965685, 3324875949, 3280061343, 3738893064, 2946628304, 856234701, 3086444665, + 694808254, 1813880914, 4127555462, 2936029435, 2523356556, 2438706698, 1835377519, + 3004798523, 3255049351, 2645300243, 77871166, 3319880385, 4067278601, 3098242181, + 3325101113, 2772478697, 801534108, 1242913681, 1974780461, 3389506397, 1336588894, + 393129198, 2783030854, 2203427106, 1109383207, 1719283460, 3041243849, 261666695, + 1025535106, 923453286, 827717779, 2807039265, 1933118943, 3274244551, 1889699541, + 1265328665, 1943061121, 1042270043, 4002841458, 372231042, 325095059, 919156966, + 1559688844, 297972731, 1058124675, 3463490561, 4186279382, 2585599754, 4031687143, + 255362872, 2718851830, 2441505029, 3559629598, 161284861, 1992175784, 3915485134, + 84323157, 141131997, 2756061329, 179913101, 3330332543, 3136211599, 2603901635, + 4227256437, 2922178905, 616595963, 3175500824, 1655253586, 327289320, 3770920662, + 848693221, 3503841802, 3931259556, 1022855830, 2859936314, 513909550, 3999727525, + 2526957429, 2821984537, 2597122982, 1412326700, 3832231820, 3168678466, 2645115637, + 321303366, 2449201471, 2555994028, 3067904292, 4272299652, 3172742871, 2373897040, + 3262703632, 2201529522, 4242934543, 2919992911, 1436165986, 2033017928, 3066712322, + 3681817762, 3970838867, 2855719673, 506845064, 3660680647, 1903888229, 483654580, + 3933223724, 3283979865, 407468681, 1168530006, 2990704403, 815024928, 3889928435, + 2491617549, 1991884684, 3507821195, 1519742370, 3811922359, 621838161, 1818574590, + 1216501288, 3838181218, 1758746829, 3152172586, 3654785573, 4187946456, 962740404, + 1598170463, 1844781445, 1083364221, 914277180, 3307998213, 280531881, 3674295517, + 983896622, 3587758496, 3506890319, 612201946, 1594301102, 3557203990, 3452646665, + 746355999, 3219848916, 579876051, 2334310192, 1891407089, 675744779, 1079614653, + 1305614539, 22268105, 350406580, 2228346597, 4142391977, 3304705805, 2643224540, + 2346692777, 3811306839, 2055912668, 163083647, 2333826953, 2151057460, 3941937039, + 1085635170, 1112366764, 735116963, 2277711192, 3718251113, 3234345339, 3079451072, + 1597196335, 535008840, 3134500306, 2002330654, 1946854270, 2150715541, 1207738170, + 2635825461, 3280844938, 3595479391, 4046757619, 3676083000, 2521337294, 4211202760, + 1127070492, 463581130, 1572521594, 1362987995, 158041764, 2152374263, 560798666, + 2464343623, 647027940, 1153071868, 3545021547, 903696024, 1085151946, 3076244929, + 4071821109, 3577654894, 347719294, 1985137777, 506009938, 3043974844, 1224943034, + 2441674287, 943278257, 1345453507, 1693293667, 2900784417, 1631023524, 1765603555, + 1126325548, 2921853563, 2146353962, 998613971, 514840483, 1023293489, 3615741723, + 2369262290, 656145243, 1354305259, 2947584320, 4176666913, 2725299359, 3261612155, + 255828942, 3388332780, 3297000689, 1523045439, 3365583669, 486896888, 1170116441, + 3755093041, 2612246577, 4165702021, 634956699, 3768307260, 1328309876, 948878956, + 3444220003, 362000903, 2864691130, 507529696, 2930154584, 3635605629, 2886604763, + 1701207604, 650477935, 1278563275, 1152046466, 2842388098, 3155750550, 1913296439, + 3796154204, 1373623833, 1829190240, 2402164973, 3534925063, 1350190204, 3766380825, + 2884139564, 4000978894, 4250218774, 1694124076, 3647405317, 3450510830, 297575619, + 3239433082, 2321033644, 1593523758, 986488941, 927914435, 1041323457, 3052530576, + 4122441236, 3679849671, 1129141796, 3385482782, 3271988188, 1637458982, 3365075758, + 3327750380, 915073093, 3973890572, 2936228140, 3281245874, 3370332651, 801307974, + 3367310492, 4025581329, 3744265314, 3141527609, 783285243, 1024284631, 1662557967, + 4288387661, 3850518314, 3999781803, 3479141110, 1226667474, 2237093609, 1871582151, + 4030420346, 593353899, 2848318175, 4135113486, 3367015917, 126745884, 3109648786, + 3558908978, 3548495984, 3114288752, 3697000294, 2490559532, 3888775359, 358178714, + 1951854291, 2275007118, 4151980360, 298857474, 3736529133, 2961456632, 196996783, + 2454543290, 1339045573, 2697951962, 2819473132, 1306910810, 1735981146, 2695155186, + 4153090923, 3374802720, 2397801981, 410696114, 589256661, 1489109647, 975636822, + 3988780217, 1904014052, 2922748256, 708153852, 3861011602, 1222762022, 3096481891, + 3901201549, 1176473345, 2150797357, 1952018225, 104031537, 1424303343, 1792851996, + 1810265303, 2810033694, 1921090978, 2889572543, 2787907754, 1596110156, 260692140, + 3729584744, 716675854, 1179319491, 1796748177, 71608814, 1742751168, 2736750551, + 1914149388, 830787397, 1386733720, 3073223633, 1151062847, 1892436425, 2187447358, + 1977238084, 363476021, 3429583327, 402781814, 781128806, 4244331924, 2494700575, + 3735841530, 3001940434, 1301696657, 152848131, 1164018513, 2733754197, 3589134520, + 1972719071, 3795946134, 3112071646, 1810134638, 955771191, 849034716, 3543622175, + 2412624989, 1849274312, 2880121793, 1482761278, 2303516731, 687795802, 1932236885, + 277889281, 2644543154, 3349742966, 498944828, 3159123266, 2094448658, 949728498, + 2624370130, 2862797877, 3455600769, 1752853916, 3196084250, 251319934, 3798443074, + 447885757, 3109173711, 3333486255, 4136551940, 1851600054, 1273576027, 3889307657, + 1009210572, 2904428566, 4066366542, 81331318, 3077464197, 2504370765, 1914551841, + 3595673347, 2279275163, 2895614653, 4004322562, 2781486796, 557234246, 3240119385, + 1474375840, 1748689310, 3190126248, 832119346, 1656610142, 2089515031, 3173461525, + 3482745970, 3396179284, 2752402192, 2967125248, 1773637785, 529966979, 276760102, + 2667014268, 2129514719, 2947217782, 4065778689, 112424943, 3049102676, 455115487, + 1843393324, 896703959, 3863808184, 2285702025, 2527940087, 1194581980, 330894106, + 1235505341, 1239511919, 513391968, 1574835140, 2637052830, 1489734447, 3462608188, + 3853430832, 44976308, 1465077781, 2984715170, 1493217435, 3842116629, 4282698888, + 3942540872, 3310013608, 3043245350, 1118287730, 3535672347, 1225429595, 3996492203, + 521109925, 2780037099, 1788178032, 3363008600, 4159442270, 1279718880, 3336828392, + 3281491867, 3678359654, 2590189543, 1755642657, 3797171953, 3940770955, 2424081100, + 2985789408, 987668658, 895616615, 2619071987, 952588159, 530271896, 2255848659, + 996616018, 1480991213, 2375501561, 1135199032, 1010174044, 3663512884, 419279564, + 2134518764, 81322211, 2909309622, 334695784, 2390255124, 484096560, 1429331258, + 1695288986, 933327260, 1144889677, 2630062765, 4136242651, 1154319202, 4178377937, + 3871010999, 978633896, 1124790846, 3872961237, 2359087957, 2713332437, 2067169477, + 3218791441, 2417082480, 2950387228, 711207861, 3905938888, 1072297456, 780058137, + 2225327061, 66019917, 2101309172, 781732246, 2915984650, 907717265, 349157973, + 2571074611, 1836556611, 242912724, 3435716719, 3021264709, 608905744, 231754520, + 3628024202, 3540870844, 2698200065, 3370666951, 679176354, 873060091, 1824713668, + 2354137422, 3956522608, 3912379829, 2941940140, 1659750710, 3554891308, 2203113685, + 2970109543, 4016203021, 2190622424, 401362631, 2136413586, 506344911, 3328130215, + 2873829637, 3883674672, 1735707197, 2851213471, 3636007066, 3576142781, 920635286, + 3414277027, 755640444, 224699414, 477577470, 3046142152, 1393292158, 1434828494, + 1060405281, 1996479056, 2678833306, 2252179338, 860115768, 1116533040, 3018630432, + 112735461, 2035706152, 763718853, 2823484451, 1754287104, 2664502817, 3585354939, + 732548627, 2175348082, 233002529, 2019361456, 3523232597, 2101058708, 2130251156, + 3667165550, 1447145780, 1368365682, 1409672843, 2662508723, 3256925752, 2808642181, + 85804983, 3369281785, 1883595751, 1123696267, 616532342, 1678240924, 1393929910, + 2830042662, 3876251704, 1968769983, 1639145269, 49550780, 374866824, 110504714, + 3303116796, 2411786404, 3099711676, 1157367152, 692800170, 681888974, 1919966704, + 672504458, 2819918429, 1169544583, 936968114, 2520693949, 1435498099, 1156122806, + 2803887655, 128491806, 1027089845, 2700739409, 288869674, 2093162014, 1199366336, + 1452631673, 589696736, 910548969, 1944921731, 1078368879, 4155043530, 2493773362, + 2118362864, 3939034270, 3366844078, 3745811564, 952783004, 1650335956, 3883669193, + 770913022, 3405982998, 2619848605, 735716470, 1907987463, 3237980455, 1662385035, + 3017028838, 3524707041, 2392747612, 3722871952, 3263101367, 620748022, 2443637548, + 3324016375, 684174418, 3861376463, 1979953065, 519879078, 1047123184, 2446164799, + 2377242800, 2933899494, 41432330, 94026108, 3267986354, 4168280259, 2705573896, + 3360605438, 3365914548, 3406807268, 1995869767, 3669573002, 1845408832, 863506975, + 3404003784, 2126651504, 14799952, 2994833187, 4176848320, 452676058, 1664278670, + 893912181, 3784216926, 2669847142, 1014136786, 3801538065, 306096503, 1668645734, + 4127485751, 305365825, 3104772045, 1005162901, 3854879829, 2646981055, 4075778792, + 637633254, 2098343553, 4068135114, 3385210946, 140099086, 1225070629, 3389371958, + 1850430746, 73349102, 490078699, 1347332780, 875789524, 209085107, 1507865019, + 1210427799, 515723706, 1868027722, 2058975055, 4270443277, 1366025695, 105646624, + 1509788154, 890549141, 3908953447, 807341053, 224539810, 659547130, 2780704405, + 1861784153, 3419852638, 2071538606, 131798003, 2420415589, 3854683022, 4000833859, + 2684812347, 2088735124, 2700426241, 2640680156, 34053997, 3906621832, 1423946216, + 516493097, 2897244512, 3703450183, 3235085733, 2708698459, 3741097740, 1551680475, + 376177994, 351898921, 552249933, 922521851, 91876389, 1044244206, 1115857743, + 3521017455, 587340439, 2190908905, 1712180168, 323825696, 3387372619, 858685730, + 3729385118, 3805205604, 2378887338, 3718437268, 477040385, 3124665320, 1808730625, + 709692573, 1936795956, 562417108, 1963827974, 3538447015, 1782736438, 2457129116, + 3990965080, 1871133930, 2972028029, 3867007479, 597477621, 4254333800, 191676744, + 2731291088, 1756855263, 1507146434, 3101630736, 2053580818, 3087659003, 412528102, + 3666146766, 1864436374, 589191486, 3034015201, 2146647765, 2772471410, 819324439, + 1925031770, 4052060806, 3928995908, 2706898868, 595467632, 240328025, 334044202, + 3728473436, 624775586, 106994446, 1102919260, 42923722, 585566309, 3050414830, + 1510865011, 1098762897, 2583442585, 614228805, 2402539396, 770290105, 308031879, + 425687430, 1218449747, 2716558921, 1929243434, 1257229287, 2176542367, 706728595, + 2508641353, 1027518972, 3961844074, 2501009749, 172703717, 2790230787, 428147405, + 3484324062, 810177957, 4162401982, 2267452562, 752562144, 1024230228, 2679993640, + 3119356373, 1876755195, 4044474080, 3571275564, 1938373684, 2893917153, 1490860820, + 973674173, 858741651, 456556454, 1434026249, 814434097, 2033138969, 4101399879, + 1949227476, 2584791597, 1714626029, 3337395475, 26118094, 1868010440, 1981814574, + 2218139522, 2782093872, 3603407779, 631332877, 1807142192, 878520063, 356991133, + 1672471476, 2194833618, 3935901757, 2991388597, 1628214501, 2032168122, 1538003368, + 314370106, 1753143679, 915672542, 3509957993, 2105542408, 1414588250, 3985143727, + 1495656623, 322802058, 3824061544, 1469606935, 1632468337, 283337945, 3439221703, + 3298553199, 2289504381, 2045978609, 1429608058, 2785464005, 2773134905, 136757740, + 3445930290, 2463142191, 2629280359, 311480240, 4204965565, 410971468, 1113488820, + 3222795507, 2025087398, 1665466436, 3943908042, 2765449529, 1257311034, 3531720973, + 20854566, 4021342790, 3785433655, 2630218088, 3644807264, 3901371304, 3640948520, + 3863350694, 849148797, 1326141603, 68161277, 1841270523, 3554223789, 3438932258, + 3877847149, 3017846090, 3147387441, 3776462537, 3347070451, 2720210508, 4097699213, + 4174324637, 1587629731, 3444565438, 4187384763, 3418638828, 1707503688, 3341712856, + 3105001597, 1780597032, 1387803205, 4119973268, 390641452, 767760632, 2358376934, + 3024095833, 2271575256, 88914562, 1265060538, 3624171743, 3693253351, 2197037019, + 1711449662, 3127263788, 2011052893, 2342704676, 2923024911, 2056538871, 3732228102, + 1787620293, 3986983402, 3508033674, 787856342, 3876073650, 1021493958, 661311052, + 1284817664, 3510068761, 2160462585, 531089334, 2341862479, 2123225605, 2975069226, + 1454648120, 2709538076, 186380217, 51898702, 701714190, 3506612549, 3320428182, + 2859339848, 3533713154, 3089919192, 1882195296, 1485897784, 2486962360, 758415433, + 236079331, 1475515301, 4008271342, 3979313520, 1531588689, 3883571822, 2800232407, + 4037999571, 3652352852, 2280544750, 583718393, 19789151, 1332193092, 772436346, + 2742865239, 3119469865, 2267207740, 2140203778, 2177551680, 4020473607, 261823465, + 1931847234, 1585658818, 2547861539, 4015864930, 1958364072, 1428836105, 1679472026, + 585029714, 4006545224, 3411279427, 3792127768, 3175098739, 3969847819, 1483422140, + 765230573, 3736767369, 1706282872, 329305623, 1040695644, 1684881032, 1272407531, + 3420521971, 3522034443, 2810848885, 1835779799, 2719122496, 4237209588, 1286977410, + 1787800433, 4223355912, 1284776076, 556616816, 4282812965, 2160424700, 1382593239, + 2516045926, 1797407435, 500920808, 419547784, 2079330089, 3497103530, 3481439636, + 3862364895, 3265084289, 2879758787, 3683708282, 2112436418, 748366440, 1662479434, + 963293795, 1836902165, 953512895, 156893596, 3742477156, 1534951954, 9867783, + 1071123538, 826169636, 1473699940, 1398802769, 3489413400, 3279858489, 3207769749, + 1844726812, 3640642524, 2750335002, 764406419, 1596487257, 1499341750, 2073530828, + 1551767693, 2947058908, 1183294128, 2827044301, 4264376236, 3544323998, 4287124850, + 846655561, 1827068722, 3819523089, 2772662699, 352633126, 1158231489, 2562677750, + 3345612115, 1147418734, 1487887911, 3309945982, 3849891818, 3652696420, 394907872, + 3103434701, 918406158, 2768564891, 3147089136, 2907819317, 2888373797, 2787755534, + 3859514895, 4232431754, 4042962333, 1281492509, 4002419688, 2820985804, 1704023742, + 1644797208, 1173714635, 2408376672, 2375732576, 1415179609, 2602999317, 593531553, + 2176498712, 2695591207, 2883179730, 2694207120, 1125555211, 1563183910, 4258821389, + 3403046251, 4017944083, 2698730212, 3338185430, 3045691178, 575737880, 685139618, + 1589153891, 412178860, 1162633267, 1944345456, 1967006725, 1024255981, 3786327406, + 542804109, 4157467010, 1727500843, 3573604690, 2111353503, 368315225, 2520704128, + 1796561125, 1626435200, 2254886653, 128840242, 808001143, 1500739954, 2063642899, + 2587711609, 107802700, 4229794616, 2670693803, 207878725, 2495604032, 3109053527, + 546978918, 1043648137, 1631274412, 365839054, 2919485597, 3150710342, 1028492706, + 2619056173, 3962815864, 2475158716, 259533563, 1457916063, 3603646061, 3372366726, + 2731736922, 1515197060, 1109717083, 4066793286, 2853741238, 618499060, 3815610005, + 2645879110, 591389873, 4155648255, 1218458888, 2043318599, 4245099975, 2766607503, + 3739099184, 2225793897, 1669959178, 1638798981, 1052699271, 875834115, 1387274512, + 497897420, 378912777, 1229567296, 2979929820, 1234317587, 2242823157, 616076844, + 1198176565, 1697526339, 2952269296, 259510251, 2292463341, 1110763338, 2834419408, + 2243897317, 1357218200, 175777809, 1599835643, 2759933309, 2740298552, 1197317042, + 391179902, 1726063293, 1567600416, 562374088, 2697654974, 743885610, 3911955293, + 595978879, 2492978036, 395457576, 3679105244, 242145418, 3206358366, 2022718346, + 2508006231, 2700101394, 2199368386, 1551314058, 3883557458, 31200113, 362076179, + 3942542681, 2170957456, 1199261872, 1711076146, 1350016364, 1091747881, 1136504139, + 926715789, 3397378635, 669618995, 807042417, 3035670333, 3354691559, 2149754843, + 3267393448, 4110214699, 938638546, 2805826602, 2110240297, 1257861712, 3673175951, + 968345689, 2938600642, 230127878, 2501408740, 3127939871, 3854966148, 608822848, + 3708451507, 2424468861, 4143788443, 3575886569, 1861677604, 149446520, 3976299715, + 2890510284, 1519510981, 1432498595, 104357924, 3965381525, 1017803683, 2903665224, + 2408631199, 10279575, 903811517, 2659504123, 275520645, 555960480, 2962976657, + 3833820553, 3810980845, 3521925688, 3963447715, 4000932047, 2355064254, 1043006088, + 4081568384, 2669175964, 777710945, 3736663677, 2929722329, 932990103, 3516119447, + 470504753, 3693725292, 1240779264, 1628339353, 3979066608, 881829213, 4110505327, + 2808632111, 960805185, 1304389985, 2591031922, 1586405142, 1704897803, 325652170, + 2697134023, 834249473, 1541424001, 2934973207, 2581256919, 3936746829, 1723826973, + 3152187997, 3596020452, 120414603, 1848962662, 1124638409, 1008154130, 1002411255, + 2287996684, 140510448, 1550243287, 334959613, 4179574024, 3449843246, 485728905, + 3866347246, 1653540960, 911548578, 1902101785, 324446669, 2326552094, 3473905612, + 1850204311, 3210536218, 422961006, 2570390056, 1505254050, 2797016905, 537654640, + 3622538924, 192474565, 1663354207, 1705814826, 3326083849, 3982462806, 1122161436, + 1325027385, 1866891611, 2284363446, ] .span(); let mut serialized_pk: Span = array![ - 1350675573, - 3521007802, - 3973994890, - 3022267814, - 412198850, - 1242482149, - 1155432711, + 1350675573, 3521007802, 3973994890, 3022267814, 412198850, 1242482149, 1155432711, 1475004518, ] .span(); diff --git a/packages/sphincs-plus/src/wots.cairo b/packages/sphincs-plus/src/wots.cairo index 828bdec..660b6d9 100644 --- a/packages/sphincs-plus/src/wots.cairo +++ b/packages/sphincs-plus/src/wots.cairo @@ -133,38 +133,8 @@ mod tests { assert_eq!( output, array![ - 0, - 1, - 0, - 2, - 0, - 3, - 0, - 4, - 0, - 5, - 0, - 6, - 0, - 7, - 0, - 8, - 1, - 0, - 2, - 0, - 3, - 0, - 4, - 0, - 5, - 0, - 6, - 0, - 7, - 0, - 8, - 0, + 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, + 7, 0, 8, 0, ], ); } @@ -201,41 +171,8 @@ mod tests { assert_eq!( output, array![ - 0, - 1, - 0, - 2, - 0, - 3, - 0, - 4, - 0, - 5, - 0, - 6, - 0, - 7, - 0, - 8, - 1, - 0, - 2, - 0, - 3, - 0, - 4, - 0, - 5, - 0, - 6, - 0, - 7, - 0, - 8, - 0, - 1, - 9, - 8, + 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, + 7, 0, 8, 0, 1, 9, 8, ], ); } @@ -282,146 +219,26 @@ mod tests { ]; let pk = wots_pk_from_sig(Default::default(), sig, message, Default::default()); let expected = array![ - 4280157821, - 1513564328, - 2473981278, - 1876372688, - 2105475624, - 2804661595, - 372022634, - 664091526, - 4027238432, - 3872223822, - 221106114, - 524906229, - 3752097775, - 3146560125, - 1879590184, - 1636129964, - 1329032692, - 1000072347, - 3970031369, - 3872965792, - 2851349356, - 1936208600, - 4116230018, - 1903880740, - 2354241252, - 2704498587, - 2531552482, - 3396990295, - 3059900203, - 2253426115, - 346500790, - 1971047600, - 1976751202, - 1558561151, - 2411291362, - 3037858944, - 132968461, - 3575066386, - 681930895, - 3305151734, - 3501974190, - 1880654097, - 3092213966, - 779706411, - 2735033803, - 2191385983, - 4067752648, - 224793655, - 1049788647, - 3648462208, - 1958295452, - 3903679462, - 1872779743, - 1742982837, - 2642993569, - 1390176031, - 2883706984, - 2246101291, - 2493097667, - 847341441, - 3420010809, - 3157666235, - 2622558776, - 3462711826, - 1129806005, - 2397760597, - 3130810852, - 3502719843, - 1789548901, - 2313604717, - 3151691158, - 2545361183, - 206247809, - 265279999, - 1583259327, - 1865531287, - 321117893, - 852595799, - 560662171, - 3090666296, - 3391532313, - 3120352875, - 1311959318, - 1580968828, - 2545213833, - 1980075718, - 2700738193, - 961781715, - 2466583066, - 3293382051, - 3386751889, - 300355772, - 1428415600, - 3099647130, - 1578840000, - 3241854699, - 4010338708, - 3087882097, - 2264660391, - 3219392681, - 1357253572, - 3859712449, - 3992315401, - 1294093020, - 530094087, - 1229019980, - 818672529, - 3160378578, - 3713034739, - 208429519, - 2762526678, - 3510982306, - 1953661473, - 3878873515, - 262957853, - 2271901417, - 3369540373, - 4292115841, - 2217881177, - 640391144, - 585932212, - 726570137, - 2030731473, - 3459932845, - 791428494, - 3675324530, - 3955694332, - 220871188, - 1568371551, - 1526534631, - 1313077632, - 1000364894, - 3919277696, - 3303850749, - 3847800427, - 2719146028, - 3796859057, - 3744444374, - 3993582049, - 3262321084, + 4280157821, 1513564328, 2473981278, 1876372688, 2105475624, 2804661595, 372022634, + 664091526, 4027238432, 3872223822, 221106114, 524906229, 3752097775, 3146560125, + 1879590184, 1636129964, 1329032692, 1000072347, 3970031369, 3872965792, 2851349356, + 1936208600, 4116230018, 1903880740, 2354241252, 2704498587, 2531552482, 3396990295, + 3059900203, 2253426115, 346500790, 1971047600, 1976751202, 1558561151, 2411291362, + 3037858944, 132968461, 3575066386, 681930895, 3305151734, 3501974190, 1880654097, + 3092213966, 779706411, 2735033803, 2191385983, 4067752648, 224793655, 1049788647, + 3648462208, 1958295452, 3903679462, 1872779743, 1742982837, 2642993569, 1390176031, + 2883706984, 2246101291, 2493097667, 847341441, 3420010809, 3157666235, 2622558776, + 3462711826, 1129806005, 2397760597, 3130810852, 3502719843, 1789548901, 2313604717, + 3151691158, 2545361183, 206247809, 265279999, 1583259327, 1865531287, 321117893, + 852595799, 560662171, 3090666296, 3391532313, 3120352875, 1311959318, 1580968828, + 2545213833, 1980075718, 2700738193, 961781715, 2466583066, 3293382051, 3386751889, + 300355772, 1428415600, 3099647130, 1578840000, 3241854699, 4010338708, 3087882097, + 2264660391, 3219392681, 1357253572, 3859712449, 3992315401, 1294093020, 530094087, + 1229019980, 818672529, 3160378578, 3713034739, 208429519, 2762526678, 3510982306, + 1953661473, 3878873515, 262957853, 2271901417, 3369540373, 4292115841, 2217881177, + 640391144, 585932212, 726570137, 2030731473, 3459932845, 791428494, 3675324530, + 3955694332, 220871188, 1568371551, 1526534631, 1313077632, 1000364894, 3919277696, + 3303850749, 3847800427, 2719146028, 3796859057, 3744444374, 3993582049, 3262321084, ]; assert_eq!(pk, expected); } From a933f1c4d02e30b6defee9bcdf944ecb5172968b Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Sun, 8 Jun 2025 21:14:42 +0100 Subject: [PATCH 4/8] Fix type inference issues --- Makefile | 5 ++++- packages/falcon/src/falcon.cairo | 2 +- packages/falcon/src/lib.cairo | 2 +- packages/sphincs-plus/Scarb.toml | 2 +- packages/sphincs-plus/src/address.cairo | 4 ++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 845ec69..3668e1e 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,10 @@ falcon-burn: scarb burn --package falcon --arguments-file packages/falcon/tests/data/args_512_1.json --output-file target/falcon.svg --open-in-browser sphincs-execute: - scarb --profile release execute --package sphincs_plus --print-resource-usage --arguments-file packages/sphincs-plus/tests/data/sha2_simple_128s.json + scarb --profile release execute \ + --package sphincs_plus \ + --print-resource-usage \ + --arguments-file packages/sphincs-plus/tests/data/sha2_simple_128s.json sphincs-burn: scarb burn --package sphincs_plus --output-file target/sphincs-plus.svg --open-in-browser diff --git a/packages/falcon/src/falcon.cairo b/packages/falcon/src/falcon.cairo index 9974a12..2286a63 100644 --- a/packages/falcon/src/falcon.cairo +++ b/packages/falcon/src/falcon.cairo @@ -326,7 +326,7 @@ mod tests { 8300, 3298, 9483, 5987, 12127, 7279, 8021, 12123, 12011, 8915, 676, 7129, 11601, 1593, 10526, 9038, 3417, 10657, 4936, 5525, ]; - if let Err(e) = verify_uncompressed(s1.span(), pk.span(), msg_point.span(), 1024) { + if let Err(e) = verify_uncompressed::<1024>(s1.span(), pk.span(), msg_point.span(), 1024) { println!("Error: {:?}", e); assert!(false); } diff --git a/packages/falcon/src/lib.cairo b/packages/falcon/src/lib.cairo index 832961e..4afca11 100644 --- a/packages/falcon/src/lib.cairo +++ b/packages/falcon/src/lib.cairo @@ -26,7 +26,7 @@ fn main(args: Args) { println!("Verifying {} signatures", attestations.len()); for attestation in attestations { - falcon::verify_uncompressed(attestation.s1, attestation.pk, attestation.msg_point, n) + falcon::verify_uncompressed::<512>(attestation.s1, attestation.pk, attestation.msg_point, n) .expect('Invalid signature'); } println!("OK"); diff --git a/packages/sphincs-plus/Scarb.toml b/packages/sphincs-plus/Scarb.toml index 6d6b46b..2ff17f7 100644 --- a/packages/sphincs-plus/Scarb.toml +++ b/packages/sphincs-plus/Scarb.toml @@ -14,5 +14,5 @@ cairo_execute = "2.11.4" cairo_test = "2.11.4" [features] -default = ["friendly"] +default = [] friendly = [] diff --git a/packages/sphincs-plus/src/address.cairo b/packages/sphincs-plus/src/address.cairo index 30a143d..04941a0 100644 --- a/packages/sphincs-plus/src/address.cairo +++ b/packages/sphincs-plus/src/address.cairo @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MIT // Available address implementations. -mod dense; -mod sparse; +pub mod dense; +pub mod sparse; // Default address packing according to the sha256-128s parameters. #[cfg(not(feature: "friendly"))] From bffacf8cd446add3141da102e41125a63d21ef60 Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Sun, 8 Jun 2025 21:22:37 +0100 Subject: [PATCH 5/8] Reduce visibility --- packages/sphincs-plus/Scarb.toml | 2 +- packages/sphincs-plus/src/hasher.cairo | 2 +- packages/sphincs-plus/src/hasher/blake2s.cairo | 4 ++-- packages/sphincs-plus/src/hasher/sha256.cairo | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sphincs-plus/Scarb.toml b/packages/sphincs-plus/Scarb.toml index 2ff17f7..6d6b46b 100644 --- a/packages/sphincs-plus/Scarb.toml +++ b/packages/sphincs-plus/Scarb.toml @@ -14,5 +14,5 @@ cairo_execute = "2.11.4" cairo_test = "2.11.4" [features] -default = [] +default = ["friendly"] friendly = [] diff --git a/packages/sphincs-plus/src/hasher.cairo b/packages/sphincs-plus/src/hasher.cairo index 750b6e5..ab6f0ca 100644 --- a/packages/sphincs-plus/src/hasher.cairo +++ b/packages/sphincs-plus/src/hasher.cairo @@ -25,7 +25,7 @@ pub type HashOutput = [u32; SPX_HASH_LEN]; /// Hash context. #[derive(Drop, Copy, Default, Debug)] pub struct SpxCtx { - pub state_seeded: HashState, + state_seeded: HashState, } /// Absorb the constant pub_seed using one round of the compression function diff --git a/packages/sphincs-plus/src/hasher/blake2s.cairo b/packages/sphincs-plus/src/hasher/blake2s.cairo index 078f4bc..1c838de 100644 --- a/packages/sphincs-plus/src/hasher/blake2s.cairo +++ b/packages/sphincs-plus/src/hasher/blake2s.cairo @@ -12,8 +12,8 @@ const BLAKE2S_256_IV: [u32; 8] = [ /// Blake2s incremental state. #[derive(Debug, Drop, Copy)] pub struct HashState { - pub h: Box<[u32; 8]>, - pub byte_len: u32, + h: Box<[u32; 8]>, + byte_len: u32, } impl HashStateDefault of Default { diff --git a/packages/sphincs-plus/src/hasher/sha256.cairo b/packages/sphincs-plus/src/hasher/sha256.cairo index f19ca7b..aaeca3a 100644 --- a/packages/sphincs-plus/src/hasher/sha256.cairo +++ b/packages/sphincs-plus/src/hasher/sha256.cairo @@ -11,8 +11,8 @@ type T8 = (u32, u32, u32, u32, u32, u32, u32, u32); /// State of the SHA-256 hasher. #[derive(Debug, Drop, Copy, Default)] pub struct HashState { - pub h: T8, - pub byte_len: u32, + h: T8, + byte_len: u32, } /// Initializes the SHA-256 hasher state with IV and resets the byte length. From 03d2295460228eb5831a0abb4d8ea08ee9a5dee4 Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Sun, 8 Jun 2025 21:34:21 +0100 Subject: [PATCH 6/8] Fix context visibility issues --- packages/sphincs-plus/Scarb.toml | 5 +++-- packages/sphincs-plus/src/address.cairo | 4 ++-- packages/sphincs-plus/src/address/dense.cairo | 1 - packages/sphincs-plus/src/address/sparse.cairo | 1 - packages/sphincs-plus/src/hasher.cairo | 4 ++-- packages/sphincs-plus/src/hasher/sha256.cairo | 4 ++-- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/sphincs-plus/Scarb.toml b/packages/sphincs-plus/Scarb.toml index 6d6b46b..7fd03d7 100644 --- a/packages/sphincs-plus/Scarb.toml +++ b/packages/sphincs-plus/Scarb.toml @@ -14,5 +14,6 @@ cairo_execute = "2.11.4" cairo_test = "2.11.4" [features] -default = ["friendly"] -friendly = [] +default = [] +blake_hash = [] +sparse_addr = [] diff --git a/packages/sphincs-plus/src/address.cairo b/packages/sphincs-plus/src/address.cairo index 04941a0..3cbfdde 100644 --- a/packages/sphincs-plus/src/address.cairo +++ b/packages/sphincs-plus/src/address.cairo @@ -7,11 +7,11 @@ pub mod dense; pub mod sparse; // Default address packing according to the sha256-128s parameters. -#[cfg(not(feature: "friendly"))] +#[cfg(not(feature: "sparse_addr"))] pub use dense::{Address, AddressTrait}; // Cairo-friendly address packing. -#[cfg(feature: "friendly")] +#[cfg(feature: "sparse_addr")] pub use sparse::{Address, AddressTrait}; #[derive(Drop)] diff --git a/packages/sphincs-plus/src/address/dense.cairo b/packages/sphincs-plus/src/address/dense.cairo index 3367bae..38b029f 100644 --- a/packages/sphincs-plus/src/address/dense.cairo +++ b/packages/sphincs-plus/src/address/dense.cairo @@ -44,7 +44,6 @@ pub struct Address { #[generate_trait] pub impl AddressImpl of AddressTrait { - #[cfg(test)] fn from_components(mut components: Array) -> Address { let w0 = components.pop_front().unwrap(); let w1 = components.pop_front().unwrap(); diff --git a/packages/sphincs-plus/src/address/sparse.cairo b/packages/sphincs-plus/src/address/sparse.cairo index 79161a1..1a5f7ef 100644 --- a/packages/sphincs-plus/src/address/sparse.cairo +++ b/packages/sphincs-plus/src/address/sparse.cairo @@ -24,7 +24,6 @@ pub struct Address { #[generate_trait] pub impl AddressImpl of AddressTrait { - #[cfg(test)] fn from_components(mut components: Array) -> Address { let layer = components.pop_front().unwrap(); let hypertree_addr_hi = components.pop_front().unwrap(); diff --git a/packages/sphincs-plus/src/hasher.cairo b/packages/sphincs-plus/src/hasher.cairo index ab6f0ca..33ed117 100644 --- a/packages/sphincs-plus/src/hasher.cairo +++ b/packages/sphincs-plus/src/hasher.cairo @@ -7,11 +7,11 @@ mod blake2s; mod sha256; // Cairo-friendly hash function (custom AIR in Stwo) -#[cfg(feature: "friendly")] +#[cfg(feature: "blake_hash")] pub use blake2s::{HashState, hash_finalize, hash_init, hash_update}; // Default hash function according to the sha256-128s parameters. -#[cfg(not(feature: "friendly"))] +#[cfg(not(feature: "blake_hash"))] pub use sha256::{HashState, hash_finalize, hash_init, hash_update}; // Imports. diff --git a/packages/sphincs-plus/src/hasher/sha256.cairo b/packages/sphincs-plus/src/hasher/sha256.cairo index aaeca3a..a5ac30f 100644 --- a/packages/sphincs-plus/src/hasher/sha256.cairo +++ b/packages/sphincs-plus/src/hasher/sha256.cairo @@ -11,8 +11,8 @@ type T8 = (u32, u32, u32, u32, u32, u32, u32, u32); /// State of the SHA-256 hasher. #[derive(Debug, Drop, Copy, Default)] pub struct HashState { - h: T8, - byte_len: u32, + pub(crate) h: T8, + pub(crate) byte_len: u32, } /// Initializes the SHA-256 hasher state with IV and resets the byte length. From 9a6df137e0a70dfeb5cb15dd6f7c9d90114b6fcc Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Sun, 8 Jun 2025 21:42:36 +0100 Subject: [PATCH 7/8] Cleanup --- Makefile | 50 ++++++++----------- README.md | 2 +- Scarb.toml | 1 - packages/sphincs-plus/src/hasher.cairo | 2 +- .../sphincs-plus/src/hasher/blake2s.cairo | 4 +- prover_params.json | 12 ----- 6 files changed, 25 insertions(+), 46 deletions(-) delete mode 100644 prover_params.json diff --git a/Makefile b/Makefile index 3668e1e..648e716 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,11 @@ TARGET_DIR = target -install-stwo: - # NOTE: rust-toolchain.toml must be the same as the one in the stwo-cairo repo +install-cairo-prove: RUSTFLAGS="-C target-cpu=native -C opt-level=3" \ cargo install \ - --git https://github.com/starkware-libs/stwo-cairo \ - --rev 61d338ee93f11a735eb5cd86f024f7a73d59d420 \ - adapted_stwo - -install-cairo-execute: - cargo install --git https://github.com/ohad-agadi/cairo.git --rev 24c4130 cairo-execute + --git https://github.com/starkware-libs/stwo-cairo \ + --rev adc68829b0e913d5a8bdf14932a45fde27a2e335 \ + cairo-prove falcon-execute: rm -rf $(TARGET_DIR)/execute/falcon \ @@ -23,33 +19,20 @@ falcon-args: falcon-build: scarb --profile release build --package falcon -falcon-cairo-execute: - rm -rf $(TARGET_DIR)/execute/falcon \ - && mkdir -p $(TARGET_DIR)/execute/falcon/execution1 \ - && cairo-execute \ - --layout all_cairo \ - --args-file packages/falcon/tests/data/args_512_1.json \ - --standalone \ - --disable-trace-padding true \ - --prebuilt \ - --trace-file $(TARGET_DIR)/execute/falcon/execution1/trace.bin \ - --memory-file $(TARGET_DIR)/execute/falcon/execution1/memory.bin \ - --air-public-input $(TARGET_DIR)/execute/falcon/execution1/air_public_input.json \ - --air-private-input $(TARGET_DIR)/execute/falcon/execution1/air_private_input.json \ - $(TARGET_DIR)/release/falcon.executable.json - falcon-prove: - adapted_stwo \ - --priv_json $(TARGET_DIR)/execute/falcon/execution1/air_private_input.json \ - --pub_json $(TARGET_DIR)/execute/falcon/execution1/air_public_input.json \ - --proof_path $(TARGET_DIR)/proof.json \ - --params_json prover_params.json \ - --verify + rm -rf $(TARGET_DIR)/execute/falcon + mkdir -p $(TARGET_DIR)/execute/falcon + cairo-prove prove \ + $(TARGET_DIR)/release/falcon.executable.json \ + $(TARGET_DIR)/execute/falcon/proof.json \ + --arguments-file packages/falcon/tests/data/args_512_1.json \ + --proof-format cairo-serde falcon-burn: scarb burn --package falcon --arguments-file packages/falcon/tests/data/args_512_1.json --output-file target/falcon.svg --open-in-browser sphincs-execute: + rm -rf $(TARGET_DIR)/execute/sphincs_plus scarb --profile release execute \ --package sphincs_plus \ --print-resource-usage \ @@ -57,3 +40,12 @@ sphincs-execute: sphincs-burn: scarb burn --package sphincs_plus --output-file target/sphincs-plus.svg --open-in-browser + +sphincs-prove: + rm -rf $(TARGET_DIR)/execute/sphincs_plus + mkdir -p $(TARGET_DIR)/execute/sphincs_plus + cairo-prove prove \ + $(TARGET_DIR)/release/sphincs_plus.executable.json \ + $(TARGET_DIR)/execute/sphincs_plus/proof.json \ + --arguments-file packages/sphincs-plus/tests/data/sha2_simple_128s.json \ + --proof-format cairo-serde diff --git a/README.md b/README.md index 37a9aae..ba24bb8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Implementation details: - [ ] Stwo proving benchmarks Follow-up: -- [ ] Sphincs+ 128s with Blake2s and 4-byte aligned address encoding +- [x] Sphincs+ 128s with Blake2s and 4-byte aligned address encoding - [ ] Falcon512 with probabilistic polynomial multiplication checking ## References diff --git a/Scarb.toml b/Scarb.toml index b1ff114..8f00bc2 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -3,4 +3,3 @@ members = ["packages/*"] [cairo] enable-gas = false -sierra-replace-ids = true diff --git a/packages/sphincs-plus/src/hasher.cairo b/packages/sphincs-plus/src/hasher.cairo index 33ed117..31fe6a1 100644 --- a/packages/sphincs-plus/src/hasher.cairo +++ b/packages/sphincs-plus/src/hasher.cairo @@ -157,7 +157,7 @@ pub fn to_hex(data: Span) -> ByteArray { crate::word_array::hex::words_to_hex(word_span) } -#[cfg(and(test, not(feature: "friendly")))] +#[cfg(and(test, not(feature: "blake_hash")))] mod tests { use crate::word_array::hex::{words_from_hex, words_to_hex}; use super::*; diff --git a/packages/sphincs-plus/src/hasher/blake2s.cairo b/packages/sphincs-plus/src/hasher/blake2s.cairo index 1c838de..b81344d 100644 --- a/packages/sphincs-plus/src/hasher/blake2s.cairo +++ b/packages/sphincs-plus/src/hasher/blake2s.cairo @@ -12,8 +12,8 @@ const BLAKE2S_256_IV: [u32; 8] = [ /// Blake2s incremental state. #[derive(Debug, Drop, Copy)] pub struct HashState { - h: Box<[u32; 8]>, - byte_len: u32, + pub(crate) h: Box<[u32; 8]>, + pub(crate) byte_len: u32, } impl HashStateDefault of Default { diff --git a/prover_params.json b/prover_params.json deleted file mode 100644 index d8446b4..0000000 --- a/prover_params.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "channel_hash": "blake2s", - "pcs_config": { - "pow_bits": 0, - "fri_config": { - "log_last_layer_degree_bound": 0, - "log_blowup_factor": 1, - "n_queries": 1 - } - }, - "preprocessed_trace": "canonical_without_pedersen" -} From f2c13834ba8416dc15a45ba6abdf586e2853ceec Mon Sep 17 00:00:00 2001 From: Michael Zaikin Date: Sun, 8 Jun 2025 21:59:01 +0100 Subject: [PATCH 8/8] Enable feature flags for execution --- Makefile | 23 ++++++++++++++++------ packages/sphincs-plus/src/lib.cairo | 9 +++++++++ packages/sphincs-plus/src/word_array.cairo | 1 + 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 648e716..7a9cd51 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ falcon-args: falcon-build: scarb --profile release build --package falcon -falcon-prove: +falcon-prove: falcon-build rm -rf $(TARGET_DIR)/execute/falcon mkdir -p $(TARGET_DIR)/execute/falcon cairo-prove prove \ @@ -29,19 +29,30 @@ falcon-prove: --proof-format cairo-serde falcon-burn: - scarb burn --package falcon --arguments-file packages/falcon/tests/data/args_512_1.json --output-file target/falcon.svg --open-in-browser + scarb burn --package falcon \ + --arguments-file packages/falcon/tests/data/args_512_1.json \ + --output-file target/falcon.svg \ + --open-in-browser + +sphincs-build: + scarb --profile release build --package sphincs_plus --features blake_hash,sparse_addr -sphincs-execute: +sphincs-execute: sphincs-build rm -rf $(TARGET_DIR)/execute/sphincs_plus scarb --profile release execute \ + --no-build \ --package sphincs_plus \ --print-resource-usage \ --arguments-file packages/sphincs-plus/tests/data/sha2_simple_128s.json -sphincs-burn: - scarb burn --package sphincs_plus --output-file target/sphincs-plus.svg --open-in-browser +sphincs-burn: sphincs-build + scarb burn --package sphincs_plus \ + --no-build \ + --output-file target/sphincs-plus.svg \ + --arguments-file packages/sphincs-plus/tests/data/sha2_simple_128s.json \ + --open-in-browser -sphincs-prove: +sphincs-prove: sphincs-build rm -rf $(TARGET_DIR)/execute/sphincs_plus mkdir -p $(TARGET_DIR)/execute/sphincs_plus cairo-prove prove \ diff --git a/packages/sphincs-plus/src/lib.cairo b/packages/sphincs-plus/src/lib.cairo index bf8fee4..8c9afdf 100644 --- a/packages/sphincs-plus/src/lib.cairo +++ b/packages/sphincs-plus/src/lib.cairo @@ -26,5 +26,14 @@ pub struct Args { fn main(args: Args) { let Args { pk, sig, message } = args; let res = sphincs::verify_128s(message.span(), sig, pk); + // TODO: generate a valid signature for blake_hash + check_result(res); +} + +#[cfg(feature: "blake_hash")] +fn check_result(res: bool) {} + +#[cfg(not(feature: "blake_hash"))] +fn check_result(res: bool) { assert(res, 'invalid signature'); } diff --git a/packages/sphincs-plus/src/word_array.cairo b/packages/sphincs-plus/src/word_array.cairo index d7988fd..106b2df 100644 --- a/packages/sphincs-plus/src/word_array.cairo +++ b/packages/sphincs-plus/src/word_array.cairo @@ -81,6 +81,7 @@ pub impl WordArrayImpl of WordArrayTrait { /// Append a 4-byte word in big-endian order. fn append_u32_be(ref self: WordArray, value: u32) { + // TODO: If last input is always 0, we can optimize this. if self.last_input_num_bytes == 0 { self.input.append(value) } else if self.last_input_num_bytes == 1 {