"+""+(item.is_alias===true?(""+item.alias+" - see "):"")+item.displayPath+""+name+" | "+""+""+item.desc+" |
"+code.outerHTML+" |
fn:
) to \
+ restrict the search to a given item kind.","Accepted kinds are: fn
, mod
, struct
, \
+ enum
, trait
, type
, macro
, \
+ and const
.","Search functions by type signature (e.g., vec -> usize
or \
+ * -> vec
)","Search multiple things at once by splitting your query with comma (e.g., \
+ str,u8
or String,struct:Vec,test
)","You can look for items with an exact name by putting double quotes around \
+ your request: \"string\"
","Look for items inside another one by searching for a path: vec::Vec
",].map(x=>""+x+"
").join("");var div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="Error type for ConfigBuilder
+UninitializedField(&'static str)
Uninitialized field
+ValidationError(String)
Custom validation error
+impl Debug for ConfigBuilderError
[src]impl Display for ConfigBuilderError
[src]impl Error for ConfigBuilderError
[src]pub fn source(&self) -> Option<&(dyn Error + 'static)>
1.30.0[src]pub fn backtrace(&self) -> Option<&Backtrace>
[src]pub fn description(&self) -> &str
1.0.0[src]pub fn cause(&self) -> Option<&dyn Error>
1.0.0[src]impl From<String> for ConfigBuilderError
[src]impl From<UninitializedFieldError> for ConfigBuilderError
[src]impl RefUnwindSafe for ConfigBuilderError
[src]impl Send for ConfigBuilderError
[src]impl Sync for ConfigBuilderError
[src]impl Unpin for ConfigBuilderError
[src]impl UnwindSafe for ConfigBuilderError
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToString for T where
T: Display + ?Sized,
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]Error type for PoWBuilder
+UninitializedField(&'static str)
Uninitialized field
+ValidationError(String)
Custom validation error
+impl Debug for PoWBuilderError
[src]impl Display for PoWBuilderError
[src]impl Error for PoWBuilderError
[src]pub fn source(&self) -> Option<&(dyn Error + 'static)>
1.30.0[src]pub fn backtrace(&self) -> Option<&Backtrace>
[src]pub fn description(&self) -> &str
1.0.0[src]pub fn cause(&self) -> Option<&dyn Error>
1.0.0[src]impl From<String> for PoWBuilderError
[src]impl From<UninitializedFieldError> for PoWBuilderError
[src]impl RefUnwindSafe for PoWBuilderError
[src]impl Send for PoWBuilderError
[src]impl Sync for PoWBuilderError
[src]impl Unpin for PoWBuilderError
[src]impl UnwindSafe for PoWBuilderError
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToString for T where
T: Display + ?Sized,
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]MCaptch's SHA256 based Proof of Work library
++ use pow_sha256::{ConfigBuilder, PoW}; + + fn main() { + let config = ConfigBuilder::default() + .salt("myrandomsaltisnotlongenoug".into()) + .build() + .unwrap(); + + let phrase = "ironmansucks"; + + const DIFFICULTY: u32 = 1000; + + let work = config.prove_work(&phrase, DIFFICULTY).unwrap(); + assert!(config.is_valid_proof(&work, &phrase)); + assert!(config.is_sufficient_difficulty(&work, DIFFICULTY)); + }
Config | Configuration for generting proof of work +Please choose a long, unique value for salt +Resistance to dictionary/rainbow attacks depend on uniqueness +of the salt + |
ConfigBuilder | Builder for |
PoW | Proof of Work over concrete type T. T can be any type that implements serde::Serialize. + |
PoWBuilder | Builder for |
ConfigBuilderError | Error type for ConfigBuilder + |
PoWBuilderError | Error type for PoWBuilder + |
Configuration for generting proof of work +Please choose a long, unique value for salt +Resistance to dictionary/rainbow attacks depend on uniqueness +of the salt
+salt: String
impl Config
[src]pub fn prove_work<T>(&self, t: &T, difficulty: u32) -> Result<PoW<T>> where
T: Serialize,
[src]Create Proof of Work over item of type T.
+Make sure difficulty is not too high. A 64 bit difficulty, +for example, takes a long time on a general purpose processor. +Returns bincode::Error if serialization fails.
+pub fn prove_work_serialized<T>(&self, prefix: &[u8], difficulty: u32) -> PoW<T> where
T: Serialize,
[src]Create Proof of Work on an already serialized item of type T. +The input is assumed to be serialized using network byte order.
+Make sure difficulty is not too high. A 64 bit difficulty, +for example, takes a long time on a general purpose processor.
+pub fn calculate<T>(&self, pow: &PoW<T>, t: &T) -> Result<u128> where
T: Serialize,
[src]Calculate the PoW score with the provided input T.
+pub fn calculate_serialized<T>(&self, pow: &PoW<T>, target: &[u8]) -> u128 where
T: Serialize,
[src]Calculate the PoW score of an already serialized T and self. +The input is assumed to be serialized using network byte order.
+pub fn is_valid_proof<T>(&self, pow: &PoW<T>, t: &T) -> bool where
T: Serialize,
[src]Verifies that the PoW is indeed generated out of the phrase provided.
+pub fn is_sufficient_difficulty<T>(
&self,
pow: &PoW<T>,
target_diff: u32
) -> bool where
T: Serialize,
[src]Checks if the PoW result is of sufficient difficulty
+impl Clone for Config
[src]impl Debug for Config
[src]impl<'de> Deserialize<'de> for Config
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl PartialEq<Config> for Config
[src]impl Serialize for Config
[src]fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error> where
__S: Serializer,
[src]impl StructuralPartialEq for Config
[src]impl RefUnwindSafe for Config
[src]impl Send for Config
[src]impl Sync for Config
[src]impl Unpin for Config
[src]impl UnwindSafe for Config
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]Builder for Config
.
impl ConfigBuilder
[src]pub fn salt(&mut self, value: String) -> &mut Self
[src]pub fn build(&self) -> Result<Config, ConfigBuilderError>
[src]impl Clone for ConfigBuilder
[src]fn clone(&self) -> ConfigBuilder
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl Default for ConfigBuilder
[src]impl RefUnwindSafe for ConfigBuilder
[src]impl Send for ConfigBuilder
[src]impl Sync for ConfigBuilder
[src]impl Unpin for ConfigBuilder
[src]impl UnwindSafe for ConfigBuilder
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]Proof of Work over concrete type T. T can be any type that implements serde::Serialize.
+nonce: u64
result: String
impl<T: Clone> Clone for PoW<T>
[src]impl<T: Debug> Debug for PoW<T>
[src]impl<'de, T> Deserialize<'de> for PoW<T>
[src]fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error> where
__D: Deserializer<'de>,
[src]impl<T: PartialEq> PartialEq<PoW<T>> for PoW<T>
[src]impl<T> Serialize for PoW<T>
[src]fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error> where
__S: Serializer,
[src]impl<T> StructuralPartialEq for PoW<T>
[src]impl<T> RefUnwindSafe for PoW<T> where
T: RefUnwindSafe,
[src]impl<T> Send for PoW<T> where
T: Send,
[src]impl<T> Sync for PoW<T> where
T: Sync,
[src]impl<T> Unpin for PoW<T> where
T: Unpin,
[src]impl<T> UnwindSafe for PoW<T> where
T: UnwindSafe,
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> DeserializeOwned for T where
T: for<'de> Deserialize<'de>,
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]Builder for PoW
.
impl<T: Clone> PoWBuilder<T>
[src]pub fn nonce(&mut self, value: u64) -> &mut Self
[src]pub fn result(&mut self, value: String) -> &mut Self
[src]pub fn build(&self) -> Result<PoW<T>, PoWBuilderError>
[src]impl<T: Clone> Clone for PoWBuilder<T>
[src]fn clone(&self) -> PoWBuilder<T>
[src]pub fn clone_from(&mut self, source: &Self)
1.0.0[src]impl<T: Clone> Default for PoWBuilder<T>
[src]impl<T> RefUnwindSafe for PoWBuilder<T> where
T: RefUnwindSafe,
[src]impl<T> Send for PoWBuilder<T> where
T: Send,
[src]impl<T> Sync for PoWBuilder<T> where
T: Sync,
[src]impl<T> Unpin for PoWBuilder<T> where
T: Unpin,
[src]impl<T> UnwindSafe for PoWBuilder<T> where
T: UnwindSafe,
[src]impl<T> Any for T where
T: 'static + ?Sized,
[src]impl<T> Borrow<T> for T where
T: ?Sized,
[src]impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]pub fn borrow_mut(&mut self) -> &mut T
[src]impl<T> From<T> for T
[src]impl<T, U> Into<U> for T where
U: From<T>,
[src]impl<T> Same<T> for T
type Output = T
Should always be Self
impl<T> ToOwned for T where
T: Clone,
[src]type Owned = T
The resulting type after obtaining ownership.
+pub fn to_owned(&self) -> T
[src]pub fn clone_into(&self, target: &mut T)
[src]impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]type Error = Infallible
The type returned in the event of a conversion error.
+pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]PoW
.",null,null],[11,"nonce","","",1,[[["u64",15]]]],[11,"result","","",1,[[["string",3]]]],[11,"build","","Builds a new PoW
.",1,[[],[["pow",3],["powbuildererror",4],["result",4]]]],[4,"PoWBuilderError","","Error type for PoWBuilder",null,null],[13,"UninitializedField","","Uninitialized field",2,null],[13,"ValidationError","","Custom validation error",2,null],[3,"Config","","Configuration for generting proof of work Please choose a …",null,null],[12,"salt","","",3,null],[3,"ConfigBuilder","","Builder for Config
.",null,null],[11,"salt","","",4,[[["string",3]]]],[11,"build","","Builds a new Config
.",4,[[],[["config",3],["configbuildererror",4],["result",4]]]],[4,"ConfigBuilderError","","Error type for ConfigBuilder",null,null],[13,"UninitializedField","","Uninitialized field",5,null],[13,"ValidationError","","Custom validation error",5,null],[11,"prove_work","","Create Proof of Work over item of type T.",3,[[["u32",15]],[["pow",3],["result",6]]]],[11,"prove_work_serialized","","Create Proof of Work on an already serialized item of …",3,[[["u32",15]],["pow",3]]],[11,"calculate","","Calculate the PoW score with the provided input T.",3,[[["pow",3]],[["u128",15],["result",6]]]],[11,"calculate_serialized","","Calculate the PoW score of an already serialized T and …",3,[[["pow",3]],["u128",15]]],[11,"is_valid_proof","","Verifies that the PoW is indeed generated out of the …",3,[[["pow",3]],["bool",15]]],[11,"is_sufficient_difficulty","","Checks if the PoW result is of sufficient difficulty",3,[[["u32",15],["pow",3]],["bool",15]]],[11,"from","","",0,[[]]],[11,"into","","",0,[[]]],[11,"to_owned","","",0,[[]]],[11,"clone_into","","",0,[[]]],[11,"borrow","","",0,[[]]],[11,"borrow_mut","","",0,[[]]],[11,"try_from","","",0,[[],["result",4]]],[11,"try_into","","",0,[[],["result",4]]],[11,"type_id","","",0,[[],["typeid",3]]],[11,"from","","",1,[[]]],[11,"into","","",1,[[]]],[11,"to_owned","","",1,[[]]],[11,"clone_into","","",1,[[]]],[11,"borrow","","",1,[[]]],[11,"borrow_mut","","",1,[[]]],[11,"try_from","","",1,[[],["result",4]]],[11,"try_into","","",1,[[],["result",4]]],[11,"type_id","","",1,[[],["typeid",3]]],[11,"from","","",2,[[]]],[11,"into","","",2,[[]]],[11,"to_string","","",2,[[],["string",3]]],[11,"borrow","","",2,[[]]],[11,"borrow_mut","","",2,[[]]],[11,"try_from","","",2,[[],["result",4]]],[11,"try_into","","",2,[[],["result",4]]],[11,"type_id","","",2,[[],["typeid",3]]],[11,"from","","",3,[[]]],[11,"into","","",3,[[]]],[11,"to_owned","","",3,[[]]],[11,"clone_into","","",3,[[]]],[11,"borrow","","",3,[[]]],[11,"borrow_mut","","",3,[[]]],[11,"try_from","","",3,[[],["result",4]]],[11,"try_into","","",3,[[],["result",4]]],[11,"type_id","","",3,[[],["typeid",3]]],[11,"from","","",4,[[]]],[11,"into","","",4,[[]]],[11,"to_owned","","",4,[[]]],[11,"clone_into","","",4,[[]]],[11,"borrow","","",4,[[]]],[11,"borrow_mut","","",4,[[]]],[11,"try_from","","",4,[[],["result",4]]],[11,"try_into","","",4,[[],["result",4]]],[11,"type_id","","",4,[[],["typeid",3]]],[11,"from","","",5,[[]]],[11,"into","","",5,[[]]],[11,"to_string","","",5,[[],["string",3]]],[11,"borrow","","",5,[[]]],[11,"borrow_mut","","",5,[[]]],[11,"try_from","","",5,[[],["result",4]]],[11,"try_into","","",5,[[],["result",4]]],[11,"type_id","","",5,[[],["typeid",3]]],[11,"from","","",2,[[["uninitializedfielderror",3]]]],[11,"from","","",2,[[["string",3]]]],[11,"from","","",5,[[["uninitializedfielderror",3]]]],[11,"from","","",5,[[["string",3]]]],[11,"clone","","",1,[[],["powbuilder",3]]],[11,"clone","","",0,[[],["pow",3]]],[11,"clone","","",4,[[],["configbuilder",3]]],[11,"clone","","",3,[[],["config",3]]],[11,"default","","",1,[[]]],[11,"default","","",4,[[]]],[11,"eq","","",0,[[["pow",3]],["bool",15]]],[11,"ne","","",0,[[["pow",3]],["bool",15]]],[11,"eq","","",3,[[["config",3]],["bool",15]]],[11,"ne","","",3,[[["config",3]],["bool",15]]],[11,"fmt","","",2,[[["formatter",3]],["result",6]]],[11,"fmt","","",0,[[["formatter",3]],["result",6]]],[11,"fmt","","",5,[[["formatter",3]],["result",6]]],[11,"fmt","","",3,[[["formatter",3]],["result",6]]],[11,"fmt","","",2,[[["formatter",3]],["result",6]]],[11,"fmt","","",5,[[["formatter",3]],["result",6]]],[11,"serialize","","",0,[[],["result",4]]],[11,"serialize","","",3,[[],["result",4]]],[11,"deserialize","","",0,[[],["result",4]]],[11,"deserialize","","",3,[[],["result",4]]]],"p":[[3,"PoW"],[3,"PoWBuilder"],[4,"PoWBuilderError"],[3,"Config"],[3,"ConfigBuilder"],[4,"ConfigBuilderError"]]}\
+}');
+addSearchOptions(searchIndex);initSearch(searchIndex);
\ No newline at end of file
diff --git a/static/api-docs/pow_sha256/0.2.1/settings.css b/static/api-docs/pow_sha256/0.2.1/settings.css
new file mode 100644
index 0000000..6709865
--- /dev/null
+++ b/static/api-docs/pow_sha256/0.2.1/settings.css
@@ -0,0 +1 @@
+.setting-line{padding:5px;position:relative;}.setting-line>div{display:inline-block;vertical-align:top;font-size:17px;padding-top:2px;}.setting-line>.title{font-size:19px;width:100%;max-width:none;border-bottom:1px solid;}.toggle{position:relative;display:inline-block;width:45px;height:27px;margin-right:20px;}.toggle input{opacity:0;position:absolute;}.select-wrapper{float:right;position:relative;height:27px;min-width:25%;}.select-wrapper select{appearance:none;-moz-appearance:none;-webkit-appearance:none;background:none;border:2px solid #ccc;padding-right:28px;width:100%;}.select-wrapper img{pointer-events:none;position:absolute;right:0;bottom:0;background:#ccc;height:100%;width:28px;padding:0px 4px;}.select-wrapper select option{color:initial;}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;-webkit-transition:.3s;transition:.3s;}.slider:before{position:absolute;content:"";height:19px;width:19px;left:4px;bottom:4px;background-color:white;-webkit-transition:.3s;transition:.3s;}input:checked+.slider{background-color:#2196F3;}input:focus+.slider{box-shadow:0 0 0 2px #0a84ff,0 0 0 6px rgba(10,132,255,0.3);}input:checked+.slider:before{-webkit-transform:translateX(19px);-ms-transform:translateX(19px);transform:translateX(19px);}.setting-line>.sub-settings{padding-left:42px;width:100%;display:block;}
\ No newline at end of file
diff --git a/static/api-docs/pow_sha256/0.2.1/settings.html b/static/api-docs/pow_sha256/0.2.1/settings.html
new file mode 100644
index 0000000..a7872cd
--- /dev/null
+++ b/static/api-docs/pow_sha256/0.2.1/settings.html
@@ -0,0 +1,7 @@
+1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +
+//! MCaptch's SHA256 based Proof of Work library +//! +//! # Example: +//! ```rust +//! use pow_sha256::{ConfigBuilder, PoW}; +//! +//! fn main() { +//! let config = ConfigBuilder::default() +//! .salt("myrandomsaltisnotlongenoug".into()) +//! .build() +//! .unwrap(); +//! +//! let phrase = "ironmansucks"; +//! +//! const DIFFICULTY: u32 = 1000; +//! +//! let work = config.prove_work(&phrase, DIFFICULTY).unwrap(); +//! assert!(config.is_valid_proof(&work, &phrase)); +//! assert!(config.is_sufficient_difficulty(&work, DIFFICULTY)); +//! } +//! ``` + +use std::marker::PhantomData; + +use derive_builder::Builder; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; + +/// Proof of Work over concrete type T. T can be any type that implements serde::Serialize. +#[derive(Serialize, Builder, Deserialize, PartialEq, Clone, Debug)] +pub struct PoW<T> { + pub nonce: u64, + pub result: String, + #[builder(default = "PhantomData", setter(skip))] + _spook: PhantomData<T>, +} + +/// Configuration for generting proof of work +/// Please choose a long, unique value for salt +/// Resistance to dictionary/rainbow attacks depend on uniqueness +/// of the salt +#[derive(Serialize, Deserialize, Builder, PartialEq, Clone, Debug)] +pub struct Config { + pub salt: String, +} + +impl Config { + /// Create Proof of Work over item of type T. + /// + /// Make sure difficulty is not too high. A 64 bit difficulty, + /// for example, takes a long time on a general purpose processor. + /// Returns bincode::Error if serialization fails. + pub fn prove_work<T>(&self, t: &T, difficulty: u32) -> bincode::Result<PoW<T>> + where + T: Serialize, + { + bincode::serialize(t).map(|v| self.prove_work_serialized(&v, difficulty)) + } + + /// Create Proof of Work on an already serialized item of type T. + /// The input is assumed to be serialized using network byte order. + /// + /// Make sure difficulty is not too high. A 64 bit difficulty, + /// for example, takes a long time on a general purpose processor. + pub fn prove_work_serialized<T>(&self, prefix: &[u8], difficulty: u32) -> PoW<T> + where + T: Serialize, + { + let prefix_sha = Sha256::new().chain(&self.salt).chain(prefix); + let mut n = 0; + let mut result = 0; + let difficulty = get_difficulty(difficulty); + while result < difficulty { + n += 1; + result = score(prefix_sha.clone(), n); + } + PoW { + nonce: n, + result: result.to_string(), + _spook: PhantomData, + } + } + + /// Calculate the PoW score with the provided input T. + pub fn calculate<T>(&self, pow: &PoW<T>, t: &T) -> bincode::Result<u128> + where + T: Serialize, + { + bincode::serialize(t).map(|v| self.calculate_serialized(pow, &v)) + } + + /// Calculate the PoW score of an already serialized T and self. + /// The input is assumed to be serialized using network byte order. + pub fn calculate_serialized<T>(&self, pow: &PoW<T>, target: &[u8]) -> u128 + where + T: Serialize, + { + score(Sha256::new().chain(&self.salt).chain(target), pow.nonce) + } + + /// Verifies that the PoW is indeed generated out of the phrase provided. + pub fn is_valid_proof<T>(&self, pow: &PoW<T>, t: &T) -> bool + where + T: Serialize, + { + match self.calculate(pow, t) { + Ok(res) => { + return if pow.result == res.to_string() { + true + } else { + false + } + } + Err(_) => return false, + } + } + + /// Checks if the PoW result is of sufficient difficulty + pub fn is_sufficient_difficulty<T>(&self, pow: &PoW<T>, target_diff: u32) -> bool + where + T: Serialize, + { + match pow.result.parse::<u128>() { + Ok(res) => return res >= get_difficulty(target_diff), + Err(_) => return false, + } + } +} + +fn score(prefix_sha: Sha256, nonce: u64) -> u128 { + first_bytes_as_u128( + prefix_sha + .chain(&nonce.to_be_bytes()) // to_be_bytes() converts to network endian + .finalize() + .as_slice(), + ) +} + +/// # Panics +/// +/// panics if inp.len() < 16 +fn first_bytes_as_u128(inp: &[u8]) -> u128 { + use bincode::config::*; + DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes() + .with_no_limit() + .with_big_endian() + .deserialize(&inp) + .unwrap() +} + +// utility function to get u128 difficulty factor from u32 +// javacript isn't capable of represnting u128 so +fn get_difficulty(difficulty_factor: u32) -> u128 { + u128::max_value() - u128::max_value() / difficulty_factor as u128 +} + +#[cfg(test)] +mod test { + use super::*; + + const DIFFICULTY: u32 = 1000; + + fn get_config() -> Config { + ConfigBuilder::default() + .salt( + "79ziepia7vhjgviiwjhnend3ofjqocsi2winc4ptqhmkvcajihywxcizewvckg9h6gs4j83v9".into(), + ) + .build() + .unwrap() + } + + #[test] + fn base_functionality() { + // Let's prove we did work targeting a phrase. + let phrase = b"Ex nihilo nihil fit.".to_vec(); + let config = get_config(); + let pw = config.prove_work(&phrase, DIFFICULTY).unwrap(); + assert!(config.calculate(&pw, &phrase).unwrap() >= get_difficulty(DIFFICULTY)); + assert!(config.is_valid_proof(&pw, &phrase)); + assert!(config.is_sufficient_difficulty(&pw, DIFFICULTY)); + } + + #[test] + fn double_pow() { + let phrase = "Ex nihilo nihil fit.".to_owned(); + let config = get_config(); + + let pw = config.prove_work(&phrase, DIFFICULTY).unwrap(); + let pwpw = config.prove_work(&pw, DIFFICULTY).unwrap(); + + assert!(config.calculate(&pw, &phrase).unwrap() >= get_difficulty(DIFFICULTY)); + assert!(config.is_valid_proof(&pw, &phrase)); + assert!(config.is_sufficient_difficulty(&pw, DIFFICULTY)); + + assert!(config.calculate(&pwpw, &pw).unwrap() >= get_difficulty(DIFFICULTY)); + assert!(config.is_valid_proof(&pwpw, &pw)); + assert!(config.is_sufficient_difficulty(&pwpw, DIFFICULTY)); + } + + #[test] + fn is_not_valid_proof() { + let phrase = "Ex nihilo nihil fit.".to_owned(); + let phrase2 = "Omne quod movetur ab alio movetur.".to_owned(); + + let config = get_config(); + let pw = config.prove_work(&phrase, DIFFICULTY).unwrap(); + + let pw2 = config.prove_work(&phrase2, DIFFICULTY).unwrap(); + + assert!(!config.is_valid_proof(&pw, &phrase2)); + assert!(!config.is_valid_proof(&pw2, &phrase)); + } + + #[test] + fn serialization_test() { + let target: u8 = 1; + let config = get_config(); + let pw = config.prove_work(&target, DIFFICULTY).unwrap(); + + let message: (u8, PoW<u8>) = (target, pw); + let message_ser = bincode::serialize(&message).unwrap(); + let recieved_message: (u8, PoW<u8>) = bincode::deserialize(&message_ser).unwrap(); + assert_eq!(recieved_message, message); + assert!(config.is_sufficient_difficulty(&message.1, DIFFICULTY)); + assert!(config.is_valid_proof(&message.1, &target)); + } +} +