Skip to content

Commit a778539

Browse files
add sha hash function support to LightAccount and LightHasher + tests
1 parent 7579e82 commit a778539

File tree

19 files changed

+309
-81
lines changed

19 files changed

+309
-81
lines changed

program-libs/hasher/src/keccak.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use crate::{
99
pub struct Keccak;
1010

1111
impl Hasher for Keccak {
12+
const ID: u8 = 2;
13+
1214
fn hash(val: &[u8]) -> Result<Hash, HasherError> {
1315
Self::hashv(&[val])
1416
}

program-libs/hasher/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub const HASH_BYTES: usize = 32;
2424
pub type Hash = [u8; HASH_BYTES];
2525

2626
pub trait Hasher {
27+
const ID: u8;
2728
fn hash(val: &[u8]) -> Result<Hash, HasherError>;
2829
fn hashv(vals: &[&[u8]]) -> Result<Hash, HasherError>;
2930
fn zero_bytes() -> ZeroBytes;

program-libs/hasher/src/poseidon.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ impl From<PoseidonSyscallError> for u64 {
7878
pub struct Poseidon;
7979

8080
impl Hasher for Poseidon {
81+
const ID: u8 = 0;
82+
8183
fn hash(val: &[u8]) -> Result<Hash, HasherError> {
8284
Self::hashv(&[val])
8385
}

program-libs/hasher/src/sha256.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
pub struct Sha256;
1010

1111
impl Hasher for Sha256 {
12+
const ID: u8 = 1;
1213
fn hash(val: &[u8]) -> Result<Hash, HasherError> {
1314
Self::hashv(&[val])
1415
}

sdk-libs/macros/src/compressible.rs

Lines changed: 120 additions & 53 deletions
Large diffs are not rendered by default.

sdk-libs/macros/src/hasher/data_hasher.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,14 @@ pub(crate) fn generate_data_hasher_impl(
3737
slices[num_flattned_fields] = element.as_slice();
3838
}
3939

40-
H::hashv(slices.as_slice())
40+
let mut result = H::hashv(slices.as_slice())?;
41+
42+
// Apply field size truncation for non-Poseidon hashers
43+
if H::ID != 0 {
44+
result[0] = 0;
45+
}
46+
47+
Ok(result)
4148
}
4249
}
4350
}
@@ -59,9 +66,16 @@ pub(crate) fn generate_data_hasher_impl(
5966
println!("DataHasher::hash inputs {:?}", debug_prints);
6067
}
6168
}
62-
H::hashv(&[
69+
let mut result = H::hashv(&[
6370
#(#data_hasher_assignments.as_slice(),)*
64-
])
71+
])?;
72+
73+
// Apply field size truncation for non-Poseidon hashers
74+
if H::ID != 0 {
75+
result[0] = 0;
76+
}
77+
78+
Ok(result)
6579
}
6680
}
6781
}

sdk-libs/macros/src/hasher/light_hasher.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::hasher::{
66
data_hasher::generate_data_hasher_impl,
77
field_processor::{process_field, FieldProcessingContext},
88
input_validator::{get_field_attribute, validate_input, FieldAttribute},
9-
to_byte_array::generate_to_byte_array_impl,
9+
to_byte_array::generate_to_byte_array_impl_with_hasher,
1010
};
1111

1212
/// - ToByteArray:
@@ -49,6 +49,14 @@ use crate::hasher::{
4949
/// - Enums, References, SmartPointers:
5050
/// - Not supported
5151
pub(crate) fn derive_light_hasher(input: ItemStruct) -> Result<TokenStream> {
52+
derive_light_hasher_with_hasher(input, &quote!(::light_hasher::Poseidon))
53+
}
54+
55+
pub(crate) fn derive_light_hasher_sha(input: ItemStruct) -> Result<TokenStream> {
56+
derive_light_hasher_with_hasher(input, &quote!(::light_hasher::Sha256))
57+
}
58+
59+
fn derive_light_hasher_with_hasher(input: ItemStruct, hasher: &TokenStream) -> Result<TokenStream> {
5260
// Validate the input structure
5361
validate_input(&input)?;
5462

@@ -74,8 +82,13 @@ pub(crate) fn derive_light_hasher(input: ItemStruct) -> Result<TokenStream> {
7482
process_field(field, i, &mut context);
7583
});
7684

77-
let to_byte_array_impl =
78-
generate_to_byte_array_impl(&input.ident, &generics, field_count, &context)?;
85+
let to_byte_array_impl = generate_to_byte_array_impl_with_hasher(
86+
&input.ident,
87+
&generics,
88+
field_count,
89+
&context,
90+
hasher,
91+
)?;
7992

8093
let data_hasher_impl = generate_data_hasher_impl(&input.ident, &generics, &context)?;
8194

sdk-libs/macros/src/hasher/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ mod input_validator;
44
mod light_hasher;
55
mod to_byte_array;
66

7-
pub(crate) use light_hasher::derive_light_hasher;
7+
pub(crate) use light_hasher::{derive_light_hasher, derive_light_hasher_sha};

sdk-libs/macros/src/hasher/to_byte_array.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ use syn::Result;
44

55
use crate::hasher::field_processor::FieldProcessingContext;
66

7-
pub(crate) fn generate_to_byte_array_impl(
7+
pub(crate) fn generate_to_byte_array_impl_with_hasher(
88
struct_name: &syn::Ident,
99
generics: &syn::Generics,
1010
field_count: usize,
1111
context: &FieldProcessingContext,
12+
hasher: &TokenStream,
1213
) -> Result<TokenStream> {
1314
let (impl_gen, type_gen, where_clause) = generics.split_for_impl();
1415

@@ -44,7 +45,7 @@ pub(crate) fn generate_to_byte_array_impl(
4445
const NUM_FIELDS: usize = #field_count;
4546

4647
fn to_byte_array(&self) -> ::std::result::Result<[u8; 32], ::light_hasher::HasherError> {
47-
::light_hasher::DataHasher::hash::<::light_hasher::Poseidon>(self)
48+
::light_hasher::DataHasher::hash::<#hasher>(self)
4849
}
4950

5051
}

sdk-libs/macros/src/lib.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
extern crate proc_macro;
22
use accounts::{process_light_accounts, process_light_system_accounts};
3-
use hasher::derive_light_hasher;
3+
use hasher::{derive_light_hasher, derive_light_hasher_sha};
44
use proc_macro::TokenStream;
55
use syn::{parse_macro_input, DeriveInput, ItemStruct};
66
use traits::process_light_traits;
@@ -193,6 +193,32 @@ pub fn light_hasher(input: TokenStream) -> TokenStream {
193193
.into()
194194
}
195195

196+
/// SHA256 variant of the LightHasher derive macro.
197+
///
198+
/// This derive macro automatically implements the `DataHasher` and `ToByteArray` traits
199+
/// for structs, using SHA256 as the hashing algorithm instead of Poseidon.
200+
///
201+
/// ## Example
202+
///
203+
/// ```ignore
204+
/// use light_sdk::sha::LightHasher;
205+
///
206+
/// #[derive(LightHasher)]
207+
/// pub struct GameState {
208+
/// #[hash]
209+
/// pub player: Pubkey, // Will be hashed to 31 bytes
210+
/// pub level: u32,
211+
/// }
212+
/// ```
213+
#[proc_macro_derive(LightHasherSha, attributes(hash, skip))]
214+
pub fn light_hasher_sha(input: TokenStream) -> TokenStream {
215+
let input = parse_macro_input!(input as ItemStruct);
216+
217+
derive_light_hasher_sha(input)
218+
.unwrap_or_else(|err| err.to_compile_error())
219+
.into()
220+
}
221+
196222
/// Automatically implements the HasCompressionInfo trait for structs that have a
197223
/// `compression_info: Option<CompressionInfo>` field.
198224
///

0 commit comments

Comments
 (0)