Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: update deps #212

Merged
merged 18 commits into from
Jul 10, 2024
2 changes: 1 addition & 1 deletion .github/workflows/format.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
toolchain: 1.78.0
override: true
components: rustfmt, clippy

Expand Down
8 changes: 1 addition & 7 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,10 @@ jobs:
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
toolchain: 1.78.0
override: true
components: rustfmt, clippy

- name: Run cargo clippy
uses: actions-rs/cargo@v1
with:
command: clippy
args: --all-targets -- -D warnings

- name: Run cargo clippy with all features
uses: actions-rs/cargo@v1
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
toolchain: 1.78.0
override: true

- name: Run cargo test
Expand Down
57 changes: 35 additions & 22 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
[package]
name = "tofn"
version = "0.2.0"
version = "1.0.0"
authors = [
"Gus Gutoski <gus@axelar.network>",
"Milap Sheth <milap@axelar.network>",
]
edition = "2018"
edition = "2021"
license = "MIT OR Apache-2.0"
rust-version = "1.78.0"

[lib]
crate-type = ["lib"]
Expand All @@ -15,40 +16,52 @@ crate-type = ["lib"]
serde = { version = "1.0", features = ["derive"] }
bincode = "1.3.3"
rand_chacha = "0.3"
hmac = "0.11"
zeroize = { version = "1.4", features = ["zeroize_derive"] }
hmac = "0.12"
zeroize = { version = "1.8", features = ["zeroize_derive"] }
rand = "0.8"
sha2 = { version = "0.10", features = [
"std",
"asm",
], default-features = false }

# k256 baggage
k256 = { version = "0.9", features = [
# Ecdsa deps
k256 = { version = "0.13", features = [
"ecdsa",
"zeroize",
], default-features = false }
der = { version = "0.7", features = ["alloc", "derive", "oid"] }
ecdsa = { version = "0.12", features = [
], default-features = false, optional = true }
ecdsa = { version = "0.16", features = [
"digest",
], default-features = false } # needed only for FromDigest trait
ed25519 = { version = ">=2.2, <2.3", features = [
], default-features = false, optional = true } # needed only for FromDigest trait
crypto-bigint = { version = "0.5", default-features = false, optional = true }

# Ed25519 deps
der = { version = "0.7", features = [
"alloc",
"derive",
"oid",
], optional = true }
ed25519 = { version = "2.2", features = [
"pkcs8",
], default-features = false }
ed25519-dalek = { version = "2.0", features = [
], default-features = false, optional = true }
ed25519-dalek = { version = "2.1", features = [
"std",
"alloc",
"digest",
"rand_core",
"zeroize",
], default_features = false }
rand = "0.8"
sha2 = { version = "0.9", features = ["std", "asm"], default-features = false }
sha3 = { version = "0.9", default-features = false }
"asm",
], default_features = false, optional = true }

# logging
tracing = { version = "0.1", default-features = false }

[dev-dependencies]
tracing-test = "0" # enable logging for tests
tracing-subscriber = { version = "0", features = [
tracing-test = "0.2" # enable logging for tests
tracing-subscriber = { version = "0.3", features = [
"env-filter",
"fmt",
], default-features = false }
goldie = "0.5"
hex = "0.4"

# Don't abort in case there is a panic to clean up data
[profile.dev]
Expand All @@ -59,5 +72,5 @@ panic = "unwind"

[features]
default = ["secp256k1", "ed25519"]
secp256k1 = []
ed25519 = []
secp256k1 = ["dep:ecdsa", "dep:k256", "dep:crypto-bigint"]
ed25519 = ["dep:ed25519", "dep:ed25519-dalek", "dep:der"]
14 changes: 4 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ Tofn provides the following:
* An implementation of ECDSA SECP256k1 signing scheme.
* An implementation of ED25519 signing scheme.

* A general-purpose SDK (software development kit) to facilitate the development and use of threshold cryptography protocols such as GG20.

## Setup

* Get the latest version of Rust stable.
* Clone this repo.
* Run `cargo build --release` to build the library.
* Run `cargo test --release` to run the tests.
* Run `cargo build` to build the library.
* Run `cargo test` to run the tests.
* Run `GOLDIE_UPDATE=1 cargo test` to generate golden files for relevant tests.

## Threshold cryptography

Expand All @@ -21,12 +20,7 @@ see this version of [tofn](https://github.com/axelarnetwork/tofn/tree/0b441ed758

## Security notes

* In our security model, we don't guarantee security if the attacker has access to the device.

## Message ordering

* We assume that an honest party's Round x message is sent before Round x + i.
* We also assume that no party receives a Round x + i message from any other party before their Round x message.
* In our security model, we don't guarantee security if the attacker has access to the device. Secret key material is zeroized on a best effort basis.

## License

Expand Down
3 changes: 3 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Domain separation for protocols/schemes
#[cfg(feature = "secp256k1")]
pub const ECDSA_TAG: u8 = 0x00;

#[cfg(feature = "ed25519")]
pub const ED25519_TAG: u8 = 0x01;
47 changes: 33 additions & 14 deletions src/crypto_tools/k256_serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,36 @@
//! [Implementing Serialize · Serde](https://serde.rs/impl-serialize.html)
//! [Implementing Deserialize · Serde](https://serde.rs/impl-deserialize.html)

use crypto_bigint::ArrayEncoding;
use ecdsa::elliptic_curve::ops::Reduce;
use ecdsa::elliptic_curve::{
consts::U33, generic_array::GenericArray, group::GroupEncoding, Field,
};
use k256::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
use k256::U256;
use rand::{CryptoRng, RngCore};
use serde::{de, de::Error, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use zeroize::Zeroize;

use crate::crypto_tools::message_digest::MessageDigest;
use crate::sdk::api::BytesVec;

/// Convert a 32-byte hash digest into a scalar as per SEC1:
/// <https://www.secg.org/sec1-v2.pdf< Section 4.1.3 steps 5-6 page 45
///
/// SEC1 specifies to subtract the secp256k1 modulus when the byte array is larger than the modulus.
impl From<&MessageDigest> for k256::Scalar {
fn from(v: &MessageDigest) -> Self {
k256::Scalar::reduce(U256::from_be_byte_array(v.0.into()))
}
}

impl From<&MessageDigest> for k256::FieldBytes {
fn from(v: &MessageDigest) -> Self {
k256::Scalar::from(v).to_bytes()
}
}

/// A wrapper for a random scalar value that is zeroized on drop
/// TODO why not just do this for Scalar below?
#[derive(Debug, Serialize, Deserialize, PartialEq, Zeroize)]
Expand Down Expand Up @@ -76,7 +96,7 @@ impl<'de> Deserialize<'de> for Scalar {
{
let bytes: [u8; 32] = Deserialize::deserialize(deserializer)?;
let field_bytes = k256::FieldBytes::from(bytes);
let scalar = k256::Scalar::from_bytes_reduced(&field_bytes);
let scalar = k256::Scalar::reduce(U256::from_be_byte_array(bytes.into()));

// ensure bytes encodes an integer less than the secp256k1 modulus
// if not then scalar.to_bytes() will differ from bytes
Expand Down Expand Up @@ -188,9 +208,9 @@ impl ProjectivePoint {

/// Decode from a SEC1-encoded curve point.
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
Some(Self(k256::ProjectivePoint::from_encoded_point(
&k256::EncodedPoint::from_bytes(bytes).ok()?,
)?))
k256::ProjectivePoint::from_encoded_point(&k256::EncodedPoint::from_bytes(bytes).ok()?)
.map(Self)
.into()
}
}

Expand Down Expand Up @@ -221,7 +241,7 @@ impl From<&k256::ProjectivePoint> for ProjectivePoint {

impl From<&SecretScalar> for ProjectivePoint {
fn from(s: &SecretScalar) -> Self {
ProjectivePoint(k256::ProjectivePoint::generator() * s.0 .0)
ProjectivePoint(k256::ProjectivePoint::GENERATOR * s.0 .0)
}
}

Expand All @@ -239,12 +259,11 @@ impl<'de> Deserialize<'de> for ProjectivePoint {
where
D: Deserializer<'de>,
{
Ok(ProjectivePoint(
Option::<_>::from(
k256::ProjectivePoint::from_encoded_point(&EncodedPoint::deserialize(deserializer)?.0)
.ok_or_else(|| {
D::Error::custom("SEC1-encoded point is not on curve secp256k (K-256)")
})?,
))
.map(Self),
)
.ok_or_else(|| D::Error::custom("SEC1-encoded point is not on curve secp256k1 (K-256)"))
}
}

Expand Down Expand Up @@ -272,16 +291,16 @@ mod tests {
let s = k256::Scalar::random(rand::thread_rng());
basic_round_trip_impl::<_, Scalar>(s, Some(32));

let p = k256::ProjectivePoint::generator() * s;
let p = k256::ProjectivePoint::GENERATOR * s;
basic_round_trip_impl::<_, ProjectivePoint>(p, None);

let hashed_msg = k256::Scalar::random(rand::thread_rng());
let ephemeral_scalar = k256::Scalar::random(rand::thread_rng());
let signature = s
.try_sign_prehashed(&ephemeral_scalar, &hashed_msg)
let (signature, _) = s
.try_sign_prehashed(ephemeral_scalar, &hashed_msg.to_bytes())
.unwrap();
p.to_affine()
.verify_prehashed(&hashed_msg, &signature)
.verify_prehashed(&hashed_msg.to_bytes(), &signature)
.unwrap();
basic_round_trip_impl::<_, Signature>(signature, None);

Expand Down
19 changes: 8 additions & 11 deletions src/crypto_tools/message_digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,24 @@ use std::{

/// Sign only 32-byte hash digests
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MessageDigest([u8; 32]);
pub struct MessageDigest(pub(super) [u8; 32]);

impl TryFrom<&[u8]> for MessageDigest {
type Error = TryFromSliceError;

fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
Ok(Self(v.try_into()?))
}
}

impl AsRef<[u8]> for MessageDigest {
fn as_ref(&self) -> &[u8] {
&self.0
impl From<[u8; 32]> for MessageDigest {
fn from(v: [u8; 32]) -> Self {
Self(v)
}
}

/// Convert a 32-byte hash digest into a scalar as per SEC1:
/// <https://www.secg.org/sec1-v2.pdf< Section 4.1.3 steps 5-6 page 45
///
/// SEC1 specifies to subtract the secp256k1 modulus when the byte array is larger than the modulus.
impl From<&MessageDigest> for k256::Scalar {
fn from(v: &MessageDigest) -> Self {
k256::Scalar::from_bytes_reduced(k256::FieldBytes::from_slice(&v.0[..]))
impl AsRef<[u8]> for MessageDigest {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
2 changes: 2 additions & 0 deletions src/crypto_tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
pub mod k256_serde;

pub mod message_digest;

#[cfg(any(feature = "secp256k1", feature = "ed25519"))]
pub mod rng;
Loading
Loading