Skip to content

Commit

Permalink
feat(objectarium): implement SHA-512 hash algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
ccamel committed Apr 9, 2023
1 parent 8df8fdf commit 550d87f
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 49 deletions.
89 changes: 56 additions & 33 deletions contracts/okp4-objectarium/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use cosmwasm_std::entry_point;
use cosmwasm_std::{to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult};
use cw2::set_contract_version;

use crate::crypto::sha256_hash;
use crate::crypto;
use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, ObjectId, QueryMsg};
use crate::state;
use crate::state::{objects, pins, Bucket, Object, Pin, BUCKET, DATA};

// version info for migration info
Expand Down Expand Up @@ -63,38 +64,44 @@ pub mod execute {
pin: bool,
) -> Result<Response, ContractError> {
let size = (data.len() as u128).into();
BUCKET.update(deps.storage, |mut bucket| -> Result<_, ContractError> {
bucket.stat.size += size;
bucket.stat.object_count += Uint128::one();
match bucket.limits {
BucketLimits {
max_object_size: Some(max),
..
} if size > max => Err(BucketError::MaxObjectSizeLimitExceeded(size, max).into()),
BucketLimits {
max_objects: Some(max),
..
} if bucket.stat.object_count > max => {
Err(BucketError::MaxObjectsLimitExceeded(bucket.stat.object_count, max).into())
}
BucketLimits {
max_object_pins: Some(max),
..
} if pin && max < Uint128::one() => {
Err(BucketError::MaxObjectPinsLimitExceeded(Uint128::one(), max).into())
}
BucketLimits {
max_total_size: Some(max),
..
} if bucket.stat.size > max => {
Err(BucketError::MaxTotalSizeLimitExceeded(bucket.stat.size, max).into())
let bucket_info =
BUCKET.update(deps.storage, |mut bucket| -> Result<_, ContractError> {
bucket.stat.size += size;
bucket.stat.object_count += Uint128::one();
match bucket.limits {
BucketLimits {
max_object_size: Some(max),
..
} if size > max => {
Err(BucketError::MaxObjectSizeLimitExceeded(size, max).into())
}
BucketLimits {
max_objects: Some(max),
..
} if bucket.stat.object_count > max => Err(
BucketError::MaxObjectsLimitExceeded(bucket.stat.object_count, max).into(),
),
BucketLimits {
max_object_pins: Some(max),
..
} if pin && max < Uint128::one() => {
Err(BucketError::MaxObjectPinsLimitExceeded(Uint128::one(), max).into())
}
BucketLimits {
max_total_size: Some(max),
..
} if bucket.stat.size > max => {
Err(BucketError::MaxTotalSizeLimitExceeded(bucket.stat.size, max).into())
}
_ => Ok(bucket),
}
_ => Ok(bucket),
}
})?;
})?;

let object = &Object {
id: sha256_hash(&data.0),
id: crypto::hash(
&crypto::HashAlgorithm::from(bucket_info.config.hash_algorithm_or_default()),
&data.0,
),
owner: info.sender.clone(),
size,
pin_count: if pin { Uint128::one() } else { Uint128::zero() },
Expand Down Expand Up @@ -354,11 +361,24 @@ pub mod query {
}
}

impl From<state::HashAlgorithm> for crypto::HashAlgorithm {
fn from(algorithm: state::HashAlgorithm) -> Self {
match algorithm {
state::HashAlgorithm::Sha256 => crypto::HashAlgorithm::Sha256,
state::HashAlgorithm::Sha512 => crypto::HashAlgorithm::Sha512,
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::error::BucketError;
use crate::msg::{BucketConfig, BucketConfigBuilder, BucketLimits, BucketLimitsBuilder, BucketResponse, HashAlgorithm, ObjectPinsResponse, ObjectResponse, ObjectsResponse, PageInfo, PaginationConfig, PaginationConfigBuilder};
use crate::msg::{
BucketConfig, BucketConfigBuilder, BucketLimits, BucketLimitsBuilder, BucketResponse,
HashAlgorithm, ObjectPinsResponse, ObjectResponse, ObjectsResponse, PageInfo,
PaginationConfig, PaginationConfigBuilder,
};
use base64::{engine::general_purpose, Engine as _};
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
use cosmwasm_std::StdError::NotFound;
Expand Down Expand Up @@ -404,12 +424,15 @@ mod tests {
bucket: "bar".to_string(),
config: BucketConfigBuilder::default()
.hash_algorithm(HashAlgorithm::Sha256)
.build().unwrap(),
.build()
.unwrap(),
limits: BucketLimitsBuilder::default()
.max_total_size(Uint128::new(20000))
.max_objects(Uint128::new(10))
.max_object_size(Uint128::new(2000))
.max_object_pins(Uint128::new(1)).build().unwrap(),
.max_object_pins(Uint128::new(1))
.build()
.unwrap(),
pagination: PaginationConfigBuilder::default()
.max_page_size(50)
.default_page_size(30)
Expand Down
31 changes: 29 additions & 2 deletions contracts/okp4-objectarium/src/crypto.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
use sha2::{Digest, Sha256};
use sha2::{Digest, Sha256, Sha512};

pub fn sha256_hash(data: &Vec<u8>) -> String {
/// HashAlgorithm is the type of the hash algorithm.
pub enum HashAlgorithm {
/// Represents the SHA-256 algorithm.
Sha256,
/// Represents the SHA-512 algorithm.
Sha512,
}

/// HashFn is the type of the function used to hash data.
pub type HashFn = fn(&Vec<u8>) -> String;

/// hash returns the hash of the given data using the given algorithm.
/// If the algorithm is not supported, an error is returned.
pub fn hash(algorithm: &HashAlgorithm, data: &Vec<u8>) -> String {
let hash_fn = match algorithm {
HashAlgorithm::Sha256 => sha256_hash,
HashAlgorithm::Sha512 => sha512_hash,
};
hash_fn(data)
}

/// sha256_hash returns the SHA-256 hash of the given data.
fn sha256_hash(data: &Vec<u8>) -> String {
base16ct::lower::encode_string(&Sha256::digest(data))
}

/// sha512_hash returns the SHA-512 hash of the given data.
fn sha512_hash(data: &Vec<u8>) -> String {
base16ct::lower::encode_string(&Sha512::digest(data))
}
12 changes: 0 additions & 12 deletions contracts/okp4-objectarium/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,6 @@ pub enum HashAlgorithm {
Sha512,
}

impl Default for HashAlgorithm {
fn default() -> Self {
HashAlgorithm::Sha256
}
}

/// BucketConfig is the type of the configuration of a bucket.
///
/// The configuration is set at the instantiation of the bucket, and is immutable and cannot be changed.
Expand All @@ -160,12 +154,6 @@ pub struct BucketConfig {
pub hash_algorithm: Option<HashAlgorithm>,
}

impl BucketConfig {
pub fn hash_algorithm_or_default(&self) -> HashAlgorithm {
self.hash_algorithm.as_ref().copied().unwrap_or_default()
}
}

/// BucketLimits is the type of the limits of a bucket.
///
/// The limits are optional and if not set, there is no limit.
Expand Down
10 changes: 8 additions & 2 deletions contracts/okp4-objectarium/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::error::BucketError;
use crate::error::BucketError::EmptyName;
use crate::msg::{ObjectResponse, PaginationConfig};
use crate::msg;
use crate::msg::{ObjectResponse, PaginationConfig};
use cosmwasm_std::{Addr, StdError, StdResult, Uint128};
use cw_storage_plus::{Index, IndexList, IndexedMap, Item, Map, MultiIndex};
use schemars::JsonSchema;
Expand Down Expand Up @@ -62,7 +62,7 @@ impl Bucket {

/// HashAlgorithm is an enumeration that defines the different hash algorithms
/// supported for hashing the content of objects.
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[derive(Serialize, Copy, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum HashAlgorithm {
/// Represents the SHA-256 algorithm.
Sha256,
Expand Down Expand Up @@ -106,6 +106,12 @@ pub struct BucketConfig {
pub hash_algorithm: Option<HashAlgorithm>,
}

impl BucketConfig {
pub fn hash_algorithm_or_default(&self) -> HashAlgorithm {
self.hash_algorithm.as_ref().copied().unwrap_or_default()
}
}

impl From<msg::BucketConfig> for BucketConfig {
fn from(config: msg::BucketConfig) -> Self {
BucketConfig {
Expand Down

0 comments on commit 550d87f

Please sign in to comment.