Skip to content

Commit

Permalink
Merge branch 'main' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
milapsheth authored Jul 10, 2024
2 parents 05a7499 + 7b02507 commit c8720d1
Show file tree
Hide file tree
Showing 21 changed files with 414 additions and 124 deletions.
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 <[email protected]>",
"Milap Sheth <[email protected]>",
]
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 (with *known vulnerabilities*) of [tofn](https://github.com/axe

## 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

0 comments on commit c8720d1

Please sign in to comment.