mirror of
https://github.com/saymrwulf/risc0-curve25519-dalek-source.git
synced 2026-09-04 20:03:40 +00:00
Merge remote-tracking branch 'hdevalence/feature/serde' into develop
This commit is contained in:
commit
0b5c143326
6 changed files with 213 additions and 1 deletions
|
|
@ -7,6 +7,7 @@ rust:
|
|||
|
||||
env:
|
||||
- TEST_COMMAND=test FEATURES=--features="yolocrypto"
|
||||
- TEST_COMMAND=test FEATURES=--features="yolocrypto serde"
|
||||
- TEST_COMMAND=test FEATURES=--features="yolocrypto nightly"
|
||||
- TEST_COMMAND=bench FEATURES=--features="yolocrypto bench"
|
||||
- TEST_COMMAND=bench FEATURES=--features="yolocrypto nightly bench"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ exclude = [
|
|||
[badges]
|
||||
travis-ci = { repository = "isislovecruft/curve25519-dalek", branch = "master"}
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.arrayref]
|
||||
version = "0.3.3"
|
||||
|
||||
|
|
@ -35,6 +39,9 @@ version = "^0.6"
|
|||
[dev-dependencies.sha2]
|
||||
version = "0.4"
|
||||
|
||||
[dev-dependencies.serde_cbor]
|
||||
version = "0.6"
|
||||
|
||||
[features]
|
||||
nightly = ["radix_51"]
|
||||
default = ["std"]
|
||||
|
|
|
|||
77
src/curve.rs
77
src/curve.rs
|
|
@ -278,6 +278,59 @@ impl CompressedMontgomeryU {
|
|||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Serde support
|
||||
// ------------------------------------------------------------------------
|
||||
// Serializes to and from `ExtendedPoint` directly, doing compression
|
||||
// and decompression internally. This means that users can create
|
||||
// structs containing `ExtendedPoint`s and use Serde's derived
|
||||
// serializers to serialize those structures.
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{self, Serialize, Deserialize, Serializer, Deserializer};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::de::Visitor;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for ExtendedPoint {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
{
|
||||
serializer.serialize_bytes(self.compress_edwards().as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> Deserialize<'de> for ExtendedPoint {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
{
|
||||
struct ExtendedPointVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ExtendedPointVisitor {
|
||||
type Value = ExtendedPoint;
|
||||
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
formatter.write_str("a valid point in Edwards y + sign format")
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<ExtendedPoint, E>
|
||||
where E: serde::de::Error
|
||||
{
|
||||
if v.len() == 32 {
|
||||
let arr32 = array_ref!(v,0,32); // &[u8;32] from &[u8]
|
||||
CompressedEdwardsY(*arr32).decompress()
|
||||
.ok_or(serde::de::Error::custom("decompression failed"))
|
||||
} else {
|
||||
Err(serde::de::Error::invalid_length(v.len(), &self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_bytes(ExtendedPointVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Internal point representations
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
@ -1557,7 +1610,7 @@ mod test {
|
|||
mod vartime {
|
||||
use super::super::*;
|
||||
use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT};
|
||||
|
||||
|
||||
/// Test double_scalar_mult_vartime vs ed25519.py
|
||||
#[test]
|
||||
fn double_scalar_mult_basepoint_vs_ed25519py() {
|
||||
|
|
@ -1576,6 +1629,28 @@ mod test {
|
|||
assert_eq!(result.compress_edwards(), DOUBLE_SCALAR_MULT_RESULT);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_cbor;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "serde")]
|
||||
fn serde_cbor_basepoint_roundtrip() {
|
||||
let output = serde_cbor::to_vec(&constants::ED25519_BASEPOINT).unwrap();
|
||||
let parsed: ExtendedPoint = serde_cbor::from_slice(&output).unwrap();
|
||||
assert_eq!(parsed.compress_edwards(), constants::BASE_CMPRSSD);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "serde")]
|
||||
fn serde_cbor_decode_invalid_fails() {
|
||||
let mut output = serde_cbor::to_vec(&constants::ED25519_BASEPOINT).unwrap();
|
||||
// CBOR apparently has two bytes of overhead for a 32-byte string.
|
||||
// Set the low byte of the compressed point to 1 to make it invalid.
|
||||
output[2] = 1;
|
||||
let parsed: Result<ExtendedPoint,_> = serde_cbor::from_slice(&output);
|
||||
assert!(parsed.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
|
|
|||
69
src/decaf.rs
69
src/decaf.rs
|
|
@ -108,6 +108,63 @@ impl Identity for CompressedDecaf {
|
|||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Serde support
|
||||
// ------------------------------------------------------------------------
|
||||
// Serializes to and from `DecafPoint` directly, doing compression
|
||||
// and decompression internally. This means that users can create
|
||||
// structs containing `DecafPoint`s and use Serde's derived
|
||||
// serializers to serialize those structures.
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{self, Serialize, Deserialize, Serializer, Deserializer};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::de::Visitor;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for DecafPoint {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
{
|
||||
serializer.serialize_bytes(self.compress().as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> Deserialize<'de> for DecafPoint {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
{
|
||||
struct DecafPointVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for DecafPointVisitor {
|
||||
type Value = DecafPoint;
|
||||
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
formatter.write_str("a valid point in Decaf format")
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<DecafPoint, E>
|
||||
where E: serde::de::Error
|
||||
{
|
||||
if v.len() == 32 {
|
||||
let arr32 = array_ref!(v,0,32); // &[u8;32] from &[u8]
|
||||
CompressedDecaf(*arr32).decompress()
|
||||
.ok_or(serde::de::Error::custom("decompression failed"))
|
||||
} else {
|
||||
Err(serde::de::Error::invalid_length(v.len(), &self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_bytes(DecafPointVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Internal point representations
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/// A point in a prime-order group.
|
||||
///
|
||||
/// XXX think about how this API should work
|
||||
|
|
@ -381,6 +438,18 @@ mod test {
|
|||
use curve::Identity;
|
||||
use super::*;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_cbor;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "serde")]
|
||||
fn serde_cbor_basepoint_roundtrip() {
|
||||
let output = serde_cbor::to_vec(&constants::DECAF_ED25519_BASEPOINT).unwrap();
|
||||
let parsed: DecafPoint = serde_cbor::from_slice(&output).unwrap();
|
||||
assert_eq!(parsed, constants::DECAF_ED25519_BASEPOINT);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn decaf_decompress_negative_s_fails() {
|
||||
// constants::d is neg, so decompression should fail as |d| != d.
|
||||
|
|
|
|||
|
|
@ -47,6 +47,11 @@ extern crate arrayref;
|
|||
extern crate generic_array;
|
||||
extern crate digest;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
extern crate serde;
|
||||
#[cfg(all(test, feature = "serde"))]
|
||||
extern crate serde_cbor;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate core;
|
||||
|
||||
|
|
|
|||
|
|
@ -185,6 +185,50 @@ impl CTAssignable for Scalar {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{self, Serialize, Deserialize, Serializer, Deserializer};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::de::Visitor;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for Scalar {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
{
|
||||
serializer.serialize_bytes(self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<'de> Deserialize<'de> for Scalar {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
{
|
||||
struct ScalarVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for ScalarVisitor {
|
||||
type Value = Scalar;
|
||||
|
||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
formatter.write_str("a 32-byte scalar value")
|
||||
}
|
||||
|
||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Scalar, E>
|
||||
where E: serde::de::Error
|
||||
{
|
||||
if v.len() == 32 {
|
||||
// array_ref turns &[u8] into &[u8;32]
|
||||
Ok(Scalar(*array_ref!(v,0,32)))
|
||||
} else {
|
||||
Err(serde::de::Error::invalid_length(v.len(), &self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_bytes(ScalarVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Scalar {
|
||||
/// Return a `Scalar` chosen uniformly at random using a user-provided RNG.
|
||||
///
|
||||
|
|
@ -827,6 +871,17 @@ mod test {
|
|||
|
||||
assert_eq!(should_be_X, X);
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_cbor;
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "serde")]
|
||||
fn serde_cbor_scalar_roundtrip() {
|
||||
let output = serde_cbor::to_vec(&X).unwrap();
|
||||
let parsed: Scalar = serde_cbor::from_slice(&output).unwrap();
|
||||
assert_eq!(parsed, X);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "bench"))]
|
||||
|
|
|
|||
Loading…
Reference in a new issue