Skip to content

Commit f227fb0

Browse files
committed
Merge branch 'long_lived/initial_datalayer' into merkle_blob
2 parents 05196e4 + 070826c commit f227fb0

19 files changed

+748
-3
lines changed

.github/workflows/build-crate.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
run: cargo fmt --all -- --files-with-diff --check
3131

3232
- name: Clippy
33-
run: cargo clippy --workspace --all-features --all-targets
33+
run: cargo clippy --workspace --all-features --all-targets -- -D warnings
3434

3535
- name: Install cargo-machete
3636
run: cargo install cargo-machete

Cargo.lock

+16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+8-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ implicit_hasher = "allow"
5252

5353
[dependencies]
5454
chia-bls = { workspace = true, optional = true }
55+
chia-secp = { workspace = true, optional = true }
5556
chia-client = { workspace = true, optional = true }
5657
chia-consensus = { workspace = true, optional = true }
5758
chia-datalayer = { workspace = true, optional = true }
@@ -72,6 +73,7 @@ ignored = ["clvmr"]
7273
[features]
7374
default = [
7475
"bls",
76+
"secp",
7577
"client",
7678
"consensus",
7779
"datalayer",
@@ -84,7 +86,8 @@ default = [
8486
"clvm-utils"
8587
]
8688

87-
bls = ["dep:chia-bls"]
89+
bls = ["dep:chia-bls", "clvm-traits/chia-bls"]
90+
secp = ["dep:chia-secp", "clvm-traits/chia-secp"]
8891
client = ["dep:chia-client"]
8992
consensus = ["dep:chia-consensus"]
9093
datalayer = ["dep:chia-datalayer"]
@@ -109,6 +112,7 @@ chia-client = { path = "./crates/chia-client", version = "0.16.0" }
109112
chia-consensus = { path = "./crates/chia-consensus", version = "0.16.0" }
110113
chia-datalayer = { path = "./crates/chia-datalayer", version = "0.16.0" }
111114
chia-protocol = { path = "./crates/chia-protocol", version = "0.16.0" }
115+
chia-secp = { path = "./crates/chia-secp", version = "0.16.0" }
112116
chia-ssl = { path = "./crates/chia-ssl", version = "0.11.0" }
113117
chia-traits = { path = "./crates/chia-traits", version = "0.15.0" }
114118
chia-puzzles = { path = "./crates/chia-puzzles", version = "0.16.0" }
@@ -159,6 +163,9 @@ blocking-threadpool = "1.0.1"
159163
libfuzzer-sys = "0.4"
160164
wasm-bindgen = "0.2.95"
161165
openssl = "0.10.68"
166+
k256 = "0.13.4"
167+
p256 = "0.13.2"
168+
rand_chacha = "0.3.1"
162169
open = "5.3.0"
163170
url = "2.5.2"
164171
percent-encoding = "2.3.1"

SECURITY.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Security Policy
2+
3+
## Reporting a Vulnerability
4+
5+
Please report security concerns to https://hackerone.com/chia_network.
6+
7+
If your security issue is established to be valid, we will reach out immediately to establish
8+
communication channels and compensate the issue reporter for responsibly reporting security bugs via
9+
our bug bounty program.

crates/chia-consensus/src/spendbundle_validation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ ff01\
405405
#[case] sk_hex: &str,
406406
) {
407407
let sk = SecretKey::from_bytes(&<[u8; 32]>::from_hex(sk_hex).unwrap()).unwrap();
408-
let sol_bytes: Vec<u8> = hex::decode(solution).unwrap().to_vec();
408+
let sol_bytes = hex::decode(solution).unwrap();
409409
let full_puz = Bytes32::new(tree_hash_atom(&[1_u8]).to_bytes());
410410
let test_coin = Coin::new(
411411
hex!("4444444444444444444444444444444444444444444444444444444444444444").into(),

crates/chia-secp/Cargo.toml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
name = "chia-secp"
3+
version = "0.16.0"
4+
edition = "2021"
5+
license = "Apache-2.0"
6+
description = "Secp256k1 and secp256r1 types for Chia"
7+
authors = ["Brandon Haggstrom <[email protected]>"]
8+
homepage = "https://github.com/Chia-Network/chia_rs"
9+
repository = "https://github.com/Chia-Network/chia_rs"
10+
11+
[lints]
12+
workspace = true
13+
14+
[features]
15+
arbitrary = ["dep:arbitrary"]
16+
17+
[dependencies]
18+
arbitrary = { workspace = true, optional = true }
19+
k256 = { workspace = true }
20+
p256 = { workspace = true }
21+
hex = { workspace = true }
22+
chia-sha2= { workspace = true }
23+
24+
[dev-dependencies]
25+
rand = { workspace = true }
26+
rand_chacha = { workspace = true }
27+
anyhow = { workspace = true }

crates/chia-secp/src/lib.rs

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
mod secp256k1;
2+
mod secp256r1;
3+
4+
pub use secp256k1::*;
5+
pub use secp256r1::*;
6+
7+
#[cfg(test)]
8+
mod tests {
9+
use rand::{Rng, SeedableRng};
10+
use rand_chacha::ChaCha8Rng;
11+
12+
use super::*;
13+
14+
#[test]
15+
fn test_secp256k1_key() -> anyhow::Result<()> {
16+
let mut rng = ChaCha8Rng::seed_from_u64(1337);
17+
18+
let sk = K1SecretKey::from_bytes(&rng.gen())?;
19+
assert_eq!(
20+
hex::encode(sk.to_bytes()),
21+
"ae491886341a539a1ccfaffcc9c78650ad1adc6270620c882b8d29bf6b9bc4cd"
22+
);
23+
assert_eq!(format!("{sk:?}"), "K1SecretKey(...)");
24+
25+
let pk = sk.public_key();
26+
assert_eq!(
27+
hex::encode(pk.to_bytes()),
28+
"02827cdbbed87e45683d448be2ea15fb72ba3732247bda18474868cf5456123fb4"
29+
);
30+
assert_eq!(
31+
format!("{pk:?}"),
32+
"K1PublicKey(02827cdbbed87e45683d448be2ea15fb72ba3732247bda18474868cf5456123fb4)"
33+
);
34+
assert_eq!(
35+
format!("{pk}"),
36+
"02827cdbbed87e45683d448be2ea15fb72ba3732247bda18474868cf5456123fb4"
37+
);
38+
39+
let message_hash: [u8; 32] = rng.gen();
40+
let sig = sk.sign_prehashed(&message_hash)?;
41+
assert_eq!(
42+
hex::encode(sig.to_bytes()),
43+
"6f07897d1d28b8698af5dec5ca06907b1304b227dc9f740b8c4065cf04d5e8653ae66aa17063e7120ee7f22fae54373b35230e259244b90400b65cf00d86c591"
44+
);
45+
assert_eq!(
46+
format!("{sig:?}"),
47+
"K1Signature(6f07897d1d28b8698af5dec5ca06907b1304b227dc9f740b8c4065cf04d5e8653ae66aa17063e7120ee7f22fae54373b35230e259244b90400b65cf00d86c591)"
48+
);
49+
assert_eq!(
50+
format!("{sig}"),
51+
"6f07897d1d28b8698af5dec5ca06907b1304b227dc9f740b8c4065cf04d5e8653ae66aa17063e7120ee7f22fae54373b35230e259244b90400b65cf00d86c591"
52+
);
53+
54+
assert!(pk.verify_prehashed(&message_hash, &sig));
55+
56+
Ok(())
57+
}
58+
59+
#[test]
60+
fn test_secp256r1_key() -> anyhow::Result<()> {
61+
let mut rng = ChaCha8Rng::seed_from_u64(1337);
62+
63+
let sk = R1SecretKey::from_bytes(&rng.gen())?;
64+
assert_eq!(
65+
hex::encode(sk.to_bytes()),
66+
"ae491886341a539a1ccfaffcc9c78650ad1adc6270620c882b8d29bf6b9bc4cd"
67+
);
68+
assert_eq!(format!("{sk:?}"), "R1SecretKey(...)");
69+
70+
let pk = sk.public_key();
71+
assert_eq!(
72+
hex::encode(pk.to_bytes()),
73+
"037dc85102f5eb7867b9580fea8b242c774173e1a47db320c798242d3a7a7579e4"
74+
);
75+
assert_eq!(
76+
format!("{pk:?}"),
77+
"R1PublicKey(037dc85102f5eb7867b9580fea8b242c774173e1a47db320c798242d3a7a7579e4)"
78+
);
79+
assert_eq!(
80+
format!("{pk}"),
81+
"037dc85102f5eb7867b9580fea8b242c774173e1a47db320c798242d3a7a7579e4"
82+
);
83+
84+
let message_hash: [u8; 32] = rng.gen();
85+
let sig = sk.sign_prehashed(&message_hash)?;
86+
assert_eq!(
87+
hex::encode(sig.to_bytes()),
88+
"550e83da8cf9b2d407ed093ae213869ebd7ceaea603920f87d535690e52b40537915d8fe3d5a96c87e700c56dc638c32f7a2954f2ba409367d1a132000cc2228"
89+
);
90+
assert_eq!(
91+
format!("{sig:?}"),
92+
"R1Signature(550e83da8cf9b2d407ed093ae213869ebd7ceaea603920f87d535690e52b40537915d8fe3d5a96c87e700c56dc638c32f7a2954f2ba409367d1a132000cc2228)"
93+
);
94+
assert_eq!(
95+
format!("{sig}"),
96+
"550e83da8cf9b2d407ed093ae213869ebd7ceaea603920f87d535690e52b40537915d8fe3d5a96c87e700c56dc638c32f7a2954f2ba409367d1a132000cc2228"
97+
);
98+
99+
assert!(pk.verify_prehashed(&message_hash, &sig));
100+
101+
Ok(())
102+
}
103+
}

crates/chia-secp/src/secp256k1.rs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
mod public_key;
2+
mod secret_key;
3+
mod signature;
4+
5+
pub use public_key::*;
6+
pub use secret_key::*;
7+
pub use signature::*;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use std::fmt;
2+
use std::hash::{Hash, Hasher};
3+
4+
use chia_sha2::Sha256;
5+
use k256::ecdsa::signature::hazmat::PrehashVerifier;
6+
use k256::ecdsa::{Error, VerifyingKey};
7+
8+
use super::K1Signature;
9+
10+
#[derive(Clone, Copy, PartialEq, Eq)]
11+
pub struct K1PublicKey(pub(crate) VerifyingKey);
12+
13+
impl Hash for K1PublicKey {
14+
fn hash<H: Hasher>(&self, state: &mut H) {
15+
self.to_bytes().hash(state);
16+
}
17+
}
18+
19+
impl fmt::Debug for K1PublicKey {
20+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21+
write!(f, "K1PublicKey({self})")
22+
}
23+
}
24+
25+
impl fmt::Display for K1PublicKey {
26+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27+
write!(f, "{}", hex::encode(self.to_bytes()))
28+
}
29+
}
30+
31+
#[cfg(feature = "arbitrary")]
32+
impl<'a> arbitrary::Arbitrary<'a> for K1PublicKey {
33+
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
34+
Self::from_bytes(&u.arbitrary()?).map_err(|_| arbitrary::Error::IncorrectFormat)
35+
}
36+
}
37+
38+
impl K1PublicKey {
39+
pub const SIZE: usize = 33;
40+
41+
pub fn to_bytes(&self) -> [u8; Self::SIZE] {
42+
self.0.to_encoded_point(true).as_ref().try_into().unwrap()
43+
}
44+
45+
pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result<Self, Error> {
46+
Ok(Self(VerifyingKey::from_sec1_bytes(bytes)?))
47+
}
48+
49+
pub fn verify_prehashed(&self, message_hash: &[u8; 32], signature: &K1Signature) -> bool {
50+
self.0.verify_prehash(message_hash, &signature.0).is_ok()
51+
}
52+
53+
pub fn fingerprint(&self) -> u32 {
54+
let mut hasher = Sha256::new();
55+
hasher.update(self.to_bytes());
56+
let hash = hasher.finalize();
57+
u32::from_be_bytes(hash[0..4].try_into().unwrap())
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use std::{
2+
fmt,
3+
hash::{Hash, Hasher},
4+
};
5+
6+
use k256::ecdsa::{Error, SigningKey};
7+
8+
use super::{K1PublicKey, K1Signature};
9+
10+
#[derive(Clone, PartialEq, Eq)]
11+
pub struct K1SecretKey(SigningKey);
12+
13+
impl Hash for K1SecretKey {
14+
fn hash<H: Hasher>(&self, state: &mut H) {
15+
self.to_bytes().hash(state);
16+
}
17+
}
18+
19+
impl fmt::Debug for K1SecretKey {
20+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21+
write!(f, "K1SecretKey(...)")
22+
}
23+
}
24+
25+
#[cfg(feature = "arbitrary")]
26+
impl<'a> arbitrary::Arbitrary<'a> for K1SecretKey {
27+
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
28+
Self::from_bytes(&u.arbitrary()?).map_err(|_| arbitrary::Error::IncorrectFormat)
29+
}
30+
}
31+
32+
impl K1SecretKey {
33+
pub fn to_bytes(&self) -> [u8; 32] {
34+
self.0.to_bytes().into()
35+
}
36+
37+
pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, Error> {
38+
Ok(Self(SigningKey::from_bytes(bytes.into())?))
39+
}
40+
41+
pub fn public_key(&self) -> K1PublicKey {
42+
K1PublicKey(*self.0.verifying_key())
43+
}
44+
45+
pub fn sign_prehashed(&self, message_hash: &[u8; 32]) -> Result<K1Signature, Error> {
46+
Ok(K1Signature(
47+
self.0.sign_prehash_recoverable(message_hash)?.0,
48+
))
49+
}
50+
}

0 commit comments

Comments
 (0)