Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Commit

Permalink
add schemars support
Browse files Browse the repository at this point in the history
  • Loading branch information
JeremyRubin committed Oct 15, 2020
1 parent 536e4af commit 9f111d5
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 8 deletions.
6 changes: 6 additions & 0 deletions Cargo.toml
Expand Up @@ -21,9 +21,15 @@ fuzztarget = [] # used by other rust-bitcoin projects to make hashes almost-noop

[dev-dependencies]
serde_test = "1.0"
serde_json = "1.0"
jsonschema-valid = "0.4.0"

[dependencies]

[dependencies.schemars]
version = "0.8.0"
optional = true

[dependencies.serde]
version = "1.0"
optional = true
Expand Down
28 changes: 27 additions & 1 deletion src/hash160.rs
Expand Up @@ -28,7 +28,13 @@ use Error;

/// Output of the Bitcoin HASH160 hash function
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
pub struct Hash([u8; 20]);
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Hash(
#[cfg_attr(feature = "schemars", schemars(schema_with="crate::util::json_hex_string::len_20"))]
[u8; 20]
);



hex_fmt_impl!(Debug, Hash);
hex_fmt_impl!(Display, Hash);
Expand Down Expand Up @@ -145,6 +151,7 @@ mod tests {
#[cfg(feature="serde")]
#[test]
fn ripemd_serde() {

use serde_test::{Configure, Token, assert_tokens};

static HASH_BYTES: [u8; 20] = [
Expand All @@ -159,6 +166,24 @@ mod tests {
assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]);
}

#[cfg(all(feature = "schemars",feature = "serde"))]
#[test]
fn jsonschema_accurate() {
static HASH_BYTES: [u8; 20] = [
0x13, 0x20, 0x72, 0xdf,
0x69, 0x09, 0x33, 0x83,
0x5e, 0xb8, 0xb6, 0xad,
0x0b, 0x77, 0xe7, 0xb6,
0xf1, 0x4a, 0xca, 0xd7,
];

let hash = hash160::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap();
let s = schemars::schema_for! (hash160::Hash);
let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap();
assert!(jsonschema_valid::Config::from_schema(&schema, None).unwrap().validate(&js).is_ok());
}
}

#[cfg(all(test, feature="unstable"))]
Expand Down Expand Up @@ -191,6 +216,7 @@ mod benches {

#[bench]
pub fn hash160_64k(bh: & mut Bencher) {

let mut engine = hash160::Hash::engine();
let bytes = [1u8; 65536];
bh.iter( || {
Expand Down
23 changes: 23 additions & 0 deletions src/hmac.rs
Expand Up @@ -29,6 +29,8 @@ use Error;

/// A hash computed from a RFC 2104 HMAC. Parameterized by the underlying hash function.
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[cfg_attr(feature = "schemars", schemars(transparent))]
pub struct Hmac<T: HashTrait>(T);

impl<T: HashTrait + str::FromStr> str::FromStr for Hmac<T> {
Expand Down Expand Up @@ -375,6 +377,27 @@ mod tests {
)],
);
}

#[cfg(all(feature = "schemars",feature = "serde"))]
#[test]
fn jsonschema_accurate() {
static HASH_BYTES: [u8; 64] = [
0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd,
0x00, 0xa4, 0x11, 0x62, 0x0b, 0x46, 0xf2, 0x0f,
0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97,
0x12, 0x1a, 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8,
0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f,
0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c,
];

let hash = Hmac::<sha512::Hash>::from_slice(&HASH_BYTES).expect("right number of bytes");
let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap();
let s = schemars::schema_for! (Hmac::<sha512::Hash>);
let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap();
assert!(jsonschema_valid::Config::from_schema(&schema, None).unwrap().validate(&js).is_ok());
}
}

#[cfg(all(test, feature="unstable"))]
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Expand Up @@ -41,6 +41,8 @@
#[cfg(feature="serde")] pub extern crate serde;
#[cfg(all(test,feature="serde"))] extern crate serde_test;

#[cfg(feature = "schemars")] extern crate schemars;

#[macro_use] mod util;
#[macro_use] mod serde_macros;
#[cfg(any(test, feature = "std"))] mod std_impls;
Expand Down
24 changes: 23 additions & 1 deletion src/ripemd160.rs
Expand Up @@ -76,7 +76,11 @@ impl EngineTrait for HashEngine {

/// Output of the RIPEMD160 hash function
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
pub struct Hash([u8; 20]);
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Hash(
#[cfg_attr(feature = "schemars", schemars(schema_with="util::json_hex_string::len_20"))]
[u8; 20]
);

hex_fmt_impl!(Debug, Hash);
hex_fmt_impl!(Display, Hash);
Expand Down Expand Up @@ -542,6 +546,24 @@ mod tests {
assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]);
}

#[cfg(all(feature = "schemars",feature = "serde"))]
#[test]
fn jsonschema_accurate() {
static HASH_BYTES: [u8; 20] = [
0x13, 0x20, 0x72, 0xdf,
0x69, 0x09, 0x33, 0x83,
0x5e, 0xb8, 0xb6, 0xad,
0x0b, 0x77, 0xe7, 0xb6,
0xf1, 0x4a, 0xca, 0xd7,
];

let hash = ripemd160::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap();
let s = schemars::schema_for! (ripemd160::Hash);
let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap();
assert!(jsonschema_valid::Config::from_schema(&schema, None).unwrap().validate(&js).is_ok());
}
}

#[cfg(all(test, feature="unstable"))]
Expand Down
24 changes: 23 additions & 1 deletion src/sha1.rs
Expand Up @@ -71,7 +71,11 @@ impl EngineTrait for HashEngine {

/// Output of the SHA1 hash function
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
pub struct Hash([u8; 20]);
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Hash(
#[cfg_attr(feature = "schemars", schemars(schema_with="util::json_hex_string::len_20"))]
[u8; 20]
);

hex_fmt_impl!(Debug, Hash);
hex_fmt_impl!(Display, Hash);
Expand Down Expand Up @@ -267,6 +271,24 @@ mod tests {
assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]);
}

#[cfg(all(feature = "schemars",feature = "serde"))]
#[test]
fn jsonschema_accurate() {
static HASH_BYTES: [u8; 20] = [
0x13, 0x20, 0x72, 0xdf,
0x69, 0x09, 0x33, 0x83,
0x5e, 0xb8, 0xb6, 0xad,
0x0b, 0x77, 0xe7, 0xb6,
0xf1, 0x4a, 0xca, 0xd7,
];

let hash = sha1::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap();
let s = schemars::schema_for! (sha1::Hash);
let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap();
assert!(jsonschema_valid::Config::from_schema(&schema, None).unwrap().validate(&js).is_ok());
}
}

#[cfg(all(test, feature="unstable"))]
Expand Down
23 changes: 22 additions & 1 deletion src/sha256.rs
Expand Up @@ -72,7 +72,11 @@ impl EngineTrait for HashEngine {

/// Output of the SHA256 hash function
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
pub struct Hash([u8; 32]);
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Hash(
#[cfg_attr(feature = "schemars", schemars(schema_with="util::json_hex_string::len_32"))]
[u8; 32]
);

impl str::FromStr for Hash {
type Err = ::hex::Error;
Expand Down Expand Up @@ -499,6 +503,23 @@ mod tests {
assert_tokens(&hash.readable(), &[Token::Str("ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c")]);
}

#[cfg(all(feature = "schemars",feature = "serde"))]
#[test]
fn jsonschema_accurate() {
static HASH_BYTES: [u8; 32] = [
0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2,
0xb7, 0x65, 0x44, 0x8c, 0x86, 0x35, 0xfb, 0x6c,
];

let hash = sha256::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap();
let s = schemars::schema_for! (sha256::Hash);
let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap();
assert!(jsonschema_valid::Config::from_schema(&schema, None).unwrap().validate(&js).is_ok());
}

#[cfg(target_arch = "wasm32")]
mod wasm_tests {
extern crate wasm_bindgen_test;
Expand Down
24 changes: 23 additions & 1 deletion src/sha256d.rs
Expand Up @@ -22,7 +22,11 @@ use Error;

/// Output of the SHA256d hash function
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
pub struct Hash([u8; 32]);
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Hash(
#[cfg_attr(feature = "schemars", schemars(schema_with="crate::util::json_hex_string::len_32"))]
[u8; 32]
);

hex_fmt_impl!(Debug, Hash);
hex_fmt_impl!(Display, Hash);
Expand Down Expand Up @@ -146,6 +150,24 @@ input: &'static str,
assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
assert_tokens(&hash.readable(), &[Token::Str("6cfb35868c4465b7c289d7d5641563aa973db6a929655282a7bf95c8257f53ef")]);
}

#[cfg(all(feature = "schemars",feature = "serde"))]
#[test]
fn jsonschema_accurate() {
static HASH_BYTES: [u8; 32] = [
0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2,
0xb7, 0x65, 0x44, 0x8c, 0x86, 0x35, 0xfb, 0x6c,
];

let hash = sha256d::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap();
let s = schemars::schema_for! (sha256d::Hash);
let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap();
assert!(jsonschema_valid::Config::from_schema(&schema, None).unwrap().validate(&js).is_ok());
}

}

#[cfg(all(test, feature="unstable"))]
Expand Down
26 changes: 25 additions & 1 deletion src/sha256t.rs
Expand Up @@ -30,7 +30,13 @@ pub trait Tag {
}

/// Output of the SHA256t hash function.
pub struct Hash<T: Tag>([u8; 32], PhantomData<T>);
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Hash<T: Tag>(
#[cfg_attr(feature = "schemars", schemars(schema_with="crate::util::json_hex_string::len_32"))]
[u8; 32],
#[cfg_attr(feature = "schemars", schemars(skip))]
PhantomData<T>
);

impl<T: Tag> Copy for Hash<T> {}
impl<T: Tag> Clone for Hash<T> {
Expand Down Expand Up @@ -237,6 +243,7 @@ mod tests {
];

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct TestHashTag;

impl sha256t::Tag for TestHashTag {
Expand All @@ -263,4 +270,21 @@ mod tests {
"29589d5122ec666ab5b4695070b6debc63881a4f85d88d93ddc90078038213ed"
);
}

#[cfg(all(feature = "schemars",feature = "serde"))]
#[test]
fn jsonschema_accurate() {
static HASH_BYTES: [u8; 32] = [
0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2,
0xb7, 0x65, 0x44, 0x8c, 0x86, 0x35, 0xfb, 0x6c,
];

let hash = TestHash::from_slice(&HASH_BYTES).expect("right number of bytes");
let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap();
let s = schemars::schema_for! (TestHash);
let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap();
assert!(jsonschema_valid::Config::from_schema(&schema, None).unwrap().validate(&js).is_ok());
}
}
27 changes: 26 additions & 1 deletion src/sha512.rs
Expand Up @@ -78,7 +78,11 @@ impl EngineTrait for HashEngine {
}

/// Output of the SHA256 hash function
pub struct Hash([u8; 64]);
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Hash(
#[cfg_attr(feature = "schemars", schemars(schema_with="util::json_hex_string::len_64"))]
[u8; 64]
);

impl Copy for Hash {}

Expand Down Expand Up @@ -436,6 +440,27 @@ mod tests {
)],
);
}

#[cfg(all(feature = "schemars",feature = "serde"))]
#[test]
fn jsonschema_accurate() {
static HASH_BYTES: [u8; 64] = [
0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd,
0x00, 0xa4, 0x11, 0x62, 0x0b, 0x46, 0xf2, 0x0f,
0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97,
0x12, 0x1a, 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8,
0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f,
0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c,
];

let hash = sha512::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap();
let s = schemars::schema_for! (sha512::Hash);
let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap();
assert!(jsonschema_valid::Config::from_schema(&schema, None).unwrap().validate(&js).is_ok());
}
}

#[cfg(all(test, feature="unstable"))]
Expand Down
20 changes: 19 additions & 1 deletion src/siphash24.rs
Expand Up @@ -196,7 +196,11 @@ impl EngineTrait for HashEngine {

/// Output of the SipHash24 hash function.
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
pub struct Hash([u8; 8]);
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Hash(
#[cfg_attr(feature = "schemars", schemars(schema_with="util::json_hex_string::len_8"))]
[u8; 8]
);

hex_fmt_impl!(Debug, Hash);
hex_fmt_impl!(Display, Hash);
Expand Down Expand Up @@ -409,6 +413,20 @@ mod tests {
state_inc.input(&[i as u8]);
}
}

#[cfg(all(feature = "schemars",feature = "serde"))]
#[test]
fn jsonschema_accurate() {
static HASH_BYTES: [u8; 8] = [
0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
];

let hash = Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap();
let s = schemars::schema_for! (Hash);
let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap();
assert!(jsonschema_valid::Config::from_schema(&schema, None).unwrap().validate(&js).is_ok());
}
}

#[cfg(all(test, feature = "unstable"))]
Expand Down

0 comments on commit 9f111d5

Please sign in to comment.