Shift from_bytes into the Point impl.
Looks like we were also computing our test cases in a slightly sketchy way, and just testing that we failed in exactly the same way. We do, but now we generate better test data.
This commit is contained in:
@@ -5,7 +5,6 @@ mod point;
|
|||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use sha2::Sha512;
|
use sha2::Sha512;
|
||||||
use self::fe::*;
|
|
||||||
use self::point::*;
|
use self::point::*;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use testing::run_test;
|
use testing::run_test;
|
||||||
@@ -134,8 +133,7 @@ impl ED25519Public {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut a = Point::new();
|
let mut a = Point::from_bytes(&self.public).unwrap(); // FIXME!!
|
||||||
x25519_ge_frombytes_vartime(&mut a, &self.public);
|
|
||||||
a.invert();
|
a.invert();
|
||||||
let h_digest = eddsa_digest(signature_r, &self.public, msg);
|
let h_digest = eddsa_digest(signature_r, &self.public, msg);
|
||||||
let h = digest_scalar(&h_digest);
|
let h = digest_scalar(&h_digest);
|
||||||
|
|||||||
@@ -35,6 +35,65 @@ impl Point {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert 32 bytes into an ED25519 point. This routine is not
|
||||||
|
/// statically timed, so don't use it if that's important to you.
|
||||||
|
pub fn from_bytes(s: &[u8]) -> Option<Point>
|
||||||
|
{
|
||||||
|
let mut h = Point::new();
|
||||||
|
let mut u = FieldElement::new();
|
||||||
|
let mut v = FieldElement::new();
|
||||||
|
let mut v3 = FieldElement::new();
|
||||||
|
let mut vxx = FieldElement::new();
|
||||||
|
let mut check = FieldElement::new();
|
||||||
|
let mut temp;
|
||||||
|
|
||||||
|
fe_frombytes(&mut h.y, s);
|
||||||
|
h.z.overwrite_with(&FieldElement::one());
|
||||||
|
fe_square(&mut u, &h.y);
|
||||||
|
fe_mul(&mut v, &u, &D);
|
||||||
|
temp = u.clone();
|
||||||
|
fe_sub(&mut u, &temp, &h.z); /* u = y^2-1 */
|
||||||
|
temp = v.clone();
|
||||||
|
fe_add(&mut v, &temp, &h.z); /* v = dy^2+1 */
|
||||||
|
|
||||||
|
fe_square(&mut v3, &v);
|
||||||
|
temp = v3.clone();
|
||||||
|
fe_mul(&mut v3, &temp, &v); /* v3 = v^3 */
|
||||||
|
fe_square(&mut h.x, &v3);
|
||||||
|
temp = h.x.clone();
|
||||||
|
fe_mul(&mut h.x, &temp, &v);
|
||||||
|
temp = h.x.clone();
|
||||||
|
fe_mul(&mut h.x, &temp, &u); /* x = uv^7 */
|
||||||
|
|
||||||
|
temp = h.x.clone();
|
||||||
|
fe_pow22523(&mut h.x, &temp); /* x = (uv^7)^((q-5)/8) */
|
||||||
|
temp = h.x.clone();
|
||||||
|
fe_mul(&mut h.x, &temp, &v3);
|
||||||
|
temp = h.x.clone();
|
||||||
|
fe_mul(&mut h.x, &temp, &u); /* x = uv^3(uv^7)^((q-5)/8) */
|
||||||
|
|
||||||
|
fe_square(&mut vxx, &h.x);
|
||||||
|
temp = vxx.clone();
|
||||||
|
fe_mul(&mut vxx, &temp, &v);
|
||||||
|
fe_sub(&mut check, &vxx, &u); /* vx^2-u */
|
||||||
|
if fe_isnonzero(&check) {
|
||||||
|
fe_add(&mut check, &vxx, &u); /* vx^2+u */
|
||||||
|
if fe_isnonzero(&check) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
temp = h.x.clone();
|
||||||
|
fe_mul(&mut h.x, &temp, &SQRTM1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if fe_isnegative(&h.x) != ((s[31] >> 7) == 1) {
|
||||||
|
temp = h.x.clone();
|
||||||
|
fe_neg(&mut h.x, &temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fe_mul(&mut h.t, &h.x, &h.y);
|
||||||
|
return Some(h);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn encode_to(&self, target: &mut [u8])
|
pub fn encode_to(&self, target: &mut [u8])
|
||||||
{
|
{
|
||||||
into_encoded_point(target, &self.x, &self.y, &self.z);
|
into_encoded_point(target, &self.x, &self.y, &self.z);
|
||||||
@@ -58,75 +117,23 @@ const SQRTM1: FieldElement = FieldElement {
|
|||||||
-272473, -25146209, -2005654, 326686, 11406482]
|
-272473, -25146209, -2005654, 326686, 11406482]
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn x25519_ge_frombytes_vartime(h: &mut Point, s: &[u8]) -> bool
|
|
||||||
{
|
|
||||||
let mut u = FieldElement::new();
|
|
||||||
let mut v = FieldElement::new();
|
|
||||||
let mut v3 = FieldElement::new();
|
|
||||||
let mut vxx = FieldElement::new();
|
|
||||||
let mut check = FieldElement::new();
|
|
||||||
let mut temp;
|
|
||||||
|
|
||||||
fe_frombytes(&mut h.y, s);
|
|
||||||
h.z.overwrite_with(&FieldElement::one());
|
|
||||||
fe_square(&mut u, &h.y);
|
|
||||||
fe_mul(&mut v, &u, &D);
|
|
||||||
temp = u.clone();
|
|
||||||
fe_sub(&mut u, &temp, &h.z); /* u = y^2-1 */
|
|
||||||
temp = v.clone();
|
|
||||||
fe_add(&mut v, &temp, &h.z); /* v = dy^2+1 */
|
|
||||||
|
|
||||||
fe_square(&mut v3, &v);
|
|
||||||
temp = v3.clone();
|
|
||||||
fe_mul(&mut v3, &temp, &v); /* v3 = v^3 */
|
|
||||||
fe_square(&mut h.x, &v3);
|
|
||||||
temp = h.x.clone();
|
|
||||||
fe_mul(&mut h.x, &temp, &v);
|
|
||||||
temp = h.x.clone();
|
|
||||||
fe_mul(&mut h.x, &temp, &u); /* x = uv^7 */
|
|
||||||
|
|
||||||
temp = h.x.clone();
|
|
||||||
fe_pow22523(&mut h.x, &temp); /* x = (uv^7)^((q-5)/8) */
|
|
||||||
temp = h.x.clone();
|
|
||||||
fe_mul(&mut h.x, &temp, &v3);
|
|
||||||
temp = h.x.clone();
|
|
||||||
fe_mul(&mut h.x, &temp, &u); /* x = uv^3(uv^7)^((q-5)/8) */
|
|
||||||
|
|
||||||
fe_square(&mut vxx, &h.x);
|
|
||||||
temp = vxx.clone();
|
|
||||||
fe_mul(&mut vxx, &temp, &v);
|
|
||||||
fe_sub(&mut check, &vxx, &u); /* vx^2-u */
|
|
||||||
if fe_isnonzero(&check) {
|
|
||||||
fe_add(&mut check, &vxx, &u); /* vx^2+u */
|
|
||||||
if fe_isnonzero(&check) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
temp = h.x.clone();
|
|
||||||
fe_mul(&mut h.x, &temp, &SQRTM1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if fe_isnegative(&h.x) != ((s[31] >> 7) == 1) {
|
|
||||||
temp = h.x.clone();
|
|
||||||
fe_neg(&mut h.x, &temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
fe_mul(&mut h.t, &h.x, &h.y);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[test]
|
#[test]
|
||||||
fn from_bytes_vartime() {
|
fn from_bytes_vartime() {
|
||||||
let fname = "testdata/ed25519/fbv.test";
|
let fname = "testdata/ed25519/fbv.test";
|
||||||
run_test(fname.to_string(), 2, |case| {
|
run_test(fname.to_string(), 3, |case| {
|
||||||
let (nega, abytes) = case.get("a").unwrap();
|
let (nega, abytes) = case.get("a").unwrap();
|
||||||
|
let (negb, bbytes) = case.get("b").unwrap();
|
||||||
let (negc, cbytes) = case.get("c").unwrap();
|
let (negc, cbytes) = case.get("c").unwrap();
|
||||||
|
|
||||||
assert!(!nega && !negc);
|
assert!(!nega && !negb && !negc);
|
||||||
let target = Point::load_test_value(&cbytes);
|
let target = Point::load_test_value(&cbytes);
|
||||||
let mut mine = Point::new();
|
let mine = Point::from_bytes(&abytes);
|
||||||
x25519_ge_frombytes_vartime(&mut mine, &abytes);
|
if bbytes.len() < cbytes.len() {
|
||||||
assert_eq!(target, mine);
|
assert!(mine.is_none());
|
||||||
|
} else {
|
||||||
|
assert_eq!(target, mine.unwrap());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1789,49 +1796,49 @@ pub fn curve25519_scalar_mask(a: &mut [u8])
|
|||||||
// fe_mul(&mut x2, &tmp2, &z2);
|
// fe_mul(&mut x2, &tmp2, &z2);
|
||||||
// fe_tobytes(out, &x2);
|
// fe_tobytes(out, &x2);
|
||||||
//}
|
//}
|
||||||
|
//
|
||||||
pub fn x25519_public_from_private(public: &mut [u8], private: &[u8])
|
//pub fn x25519_public_from_private(public: &mut [u8], private: &[u8])
|
||||||
{
|
//{
|
||||||
assert_eq!(private.len(), 32);
|
// assert_eq!(private.len(), 32);
|
||||||
assert_eq!(public.len(), 32);
|
// assert_eq!(public.len(), 32);
|
||||||
|
//
|
||||||
let mut e = [0; 32];
|
// let mut e = [0; 32];
|
||||||
e.copy_from_slice(private);
|
// e.copy_from_slice(private);
|
||||||
curve25519_scalar_mask(&mut e);
|
// curve25519_scalar_mask(&mut e);
|
||||||
|
//
|
||||||
#[allow(non_snake_case)]
|
// #[allow(non_snake_case)]
|
||||||
let mut A = Point::new();
|
// let mut A = Point::new();
|
||||||
x25519_ge_scalarmult_base(&mut A, &e);
|
// x25519_ge_scalarmult_base(&mut A, &e);
|
||||||
|
//
|
||||||
/* We only need the u-coordinate of the curve25519 point. The map is
|
// /* We only need the u-coordinate of the curve25519 point. The map is
|
||||||
* u=(y+1)/(1-y). Since y=Y/Z, this gives u=(Z+Y)/(Z-Y). */
|
// * u=(y+1)/(1-y). Since y=Y/Z, this gives u=(Z+Y)/(Z-Y). */
|
||||||
let mut zplusy = FieldElement::new();
|
// let mut zplusy = FieldElement::new();
|
||||||
let mut zminusy = FieldElement::new();
|
// let mut zminusy = FieldElement::new();
|
||||||
fe_add(&mut zplusy, &A.z, &A.y);
|
// fe_add(&mut zplusy, &A.z, &A.y);
|
||||||
fe_sub(&mut zminusy, &A.z, &A.y);
|
// fe_sub(&mut zminusy, &A.z, &A.y);
|
||||||
let zminusy_inv = fe_invert(&zminusy);
|
// let zminusy_inv = fe_invert(&zminusy);
|
||||||
let copy = zplusy.clone();
|
// let copy = zplusy.clone();
|
||||||
fe_mul(&mut zplusy, ©, &zminusy_inv);
|
// fe_mul(&mut zplusy, ©, &zminusy_inv);
|
||||||
fe_tobytes(public, &zplusy);
|
// fe_tobytes(public, &zplusy);
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
#[cfg(test)]
|
//#[cfg(test)]
|
||||||
#[test]
|
//#[test]
|
||||||
fn public_from_private() {
|
//fn public_from_private() {
|
||||||
let fname = "testdata/ed25519/pubfrompriv.test";
|
// let fname = "testdata/ed25519/pubfrompriv.test";
|
||||||
run_test(fname.to_string(), 2, |case| {
|
// run_test(fname.to_string(), 2, |case| {
|
||||||
let (nega, abytes) = case.get("a").unwrap();
|
// let (nega, abytes) = case.get("a").unwrap();
|
||||||
let (negb, bbytes) = case.get("b").unwrap();
|
// let (negb, bbytes) = case.get("b").unwrap();
|
||||||
|
//
|
||||||
assert!(!nega && !negb);
|
// assert!(!nega && !negb);
|
||||||
let mut mine = [0; 32];
|
// let mut mine = [0; 32];
|
||||||
x25519_public_from_private(&mut mine, abytes);
|
// x25519_public_from_private(&mut mine, abytes);
|
||||||
for i in 0..32 {
|
// for i in 0..32 {
|
||||||
assert_eq!(mine[i], bbytes[i]);
|
// assert_eq!(mine[i], bbytes[i]);
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
fn into_encoded_point(bytes: &mut [u8], x: &FieldElement, y: &FieldElement, z: &FieldElement)
|
fn into_encoded_point(bytes: &mut [u8], x: &FieldElement, y: &FieldElement, z: &FieldElement)
|
||||||
{
|
{
|
||||||
let mut x_over_z = FieldElement::new();
|
let mut x_over_z = FieldElement::new();
|
||||||
|
|||||||
@@ -256,18 +256,22 @@ fbvTests = Task {
|
|||||||
taskCount = cTEST_COUNT
|
taskCount = cTEST_COUNT
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
go (memory0, drg0) =
|
go (memory0, drg0) =
|
||||||
do let (abytes, drg1) = withDRG drg0 (getRandomBytes 32)
|
do let (abytes, drg1) = withDRG drg0 (getRandomBytes 32)
|
||||||
useAsCString abytes $ \ aptr ->
|
useAsCString abytes $ \ aptr ->
|
||||||
do let aptr' = castPtr aptr :: Ptr PackedBytes
|
do let aptr' = castPtr aptr :: Ptr PackedBytes
|
||||||
curve25519_scalar_mask aptr'
|
curve25519_scalar_mask aptr'
|
||||||
alloca $ \ dest ->
|
alloca $ \ dest ->
|
||||||
do clearSpace dest
|
do clearSpace dest
|
||||||
point_frombytes dest aptr'
|
ok <- point_frombytes dest aptr'
|
||||||
a <- pack `fmap` peekArray 32 (castPtr aptr)
|
a <- pack `fmap` peekArray 32 (castPtr aptr)
|
||||||
c <- pack `fmap` peekArray (4 * 10 * 4) (castPtr dest)
|
c <- pack `fmap` peekArray (4 * 10 * 4) (castPtr dest)
|
||||||
let res = Map.fromList [("a", showBin a), ("c", showBin c)]
|
let c' | ok = c
|
||||||
return (res, toNumber abytes, (memory0, drg1))
|
| otherwise = BS.empty
|
||||||
|
let res = Map.fromList [("a", showBin a),
|
||||||
|
("b", showBin c'),
|
||||||
|
("c", showBin c)]
|
||||||
|
return (res, if ok then (toNumber abytes) else 0, (memory0, drg1))
|
||||||
|
|
||||||
conversionTests :: Task
|
conversionTests :: Task
|
||||||
conversionTests = Task {
|
conversionTests = Task {
|
||||||
@@ -566,12 +570,18 @@ instance Storable Point3 where
|
|||||||
poke p (P3 v) = pokeArray (castPtr p) v
|
poke p (P3 v) = pokeArray (castPtr p) v
|
||||||
|
|
||||||
randomPoint3 :: SystemRandom -> (Ptr Point3 -> SystemRandom -> IO a) -> IO a
|
randomPoint3 :: SystemRandom -> (Ptr Point3 -> SystemRandom -> IO a) -> IO a
|
||||||
randomPoint3 drg action =
|
randomPoint3 drg0 action = allocaArray (4 * 10) (go drg0)
|
||||||
randomPackedBytes drg $ \ aptr drg' ->
|
where
|
||||||
allocaArray (4 * 10) $ \ dest ->
|
go drg dest =
|
||||||
do clearSpace dest
|
do mres <- randomPackedBytes drg $ \ aptr drg' ->
|
||||||
point_frombytes dest aptr
|
do clearSpace dest
|
||||||
action (castPtr dest) drg'
|
worked <- point_frombytes dest aptr
|
||||||
|
if worked
|
||||||
|
then Right `fmap` action (castPtr dest) drg'
|
||||||
|
else return (Left drg')
|
||||||
|
case mres of
|
||||||
|
Right x -> return x
|
||||||
|
Left drg' -> go drg' dest
|
||||||
|
|
||||||
data PointCached = PC [Element]
|
data PointCached = PC [Element]
|
||||||
|
|
||||||
@@ -690,7 +700,7 @@ foreign import ccall unsafe "fe_sq2"
|
|||||||
foreign import ccall unsafe "fe_pow22523"
|
foreign import ccall unsafe "fe_pow22523"
|
||||||
fe_pow22523 :: Ptr Element -> Ptr Element -> IO ()
|
fe_pow22523 :: Ptr Element -> Ptr Element -> IO ()
|
||||||
foreign import ccall unsafe "GFp_x25519_ge_frombytes_vartime"
|
foreign import ccall unsafe "GFp_x25519_ge_frombytes_vartime"
|
||||||
point_frombytes :: Ptr Point3 -> Ptr PackedBytes -> IO ()
|
point_frombytes :: Ptr Point3 -> Ptr PackedBytes -> IO Bool
|
||||||
foreign import ccall unsafe "x25519_ge_p3_to_cached"
|
foreign import ccall unsafe "x25519_ge_p3_to_cached"
|
||||||
p3_to_cached :: Ptr PointCached -> Ptr Point3 -> IO ()
|
p3_to_cached :: Ptr PointCached -> Ptr Point3 -> IO ()
|
||||||
foreign import ccall unsafe "x25519_ge_p1p1_to_p2"
|
foreign import ccall unsafe "x25519_ge_p1p1_to_p2"
|
||||||
@@ -722,4 +732,4 @@ foreign import ccall unsafe "GFp_x25519_sc_reduce"
|
|||||||
foreign import ccall unsafe "GFp_x25519_sc_muladd"
|
foreign import ccall unsafe "GFp_x25519_sc_muladd"
|
||||||
sc_muladd :: Ptr PackedBytes -> Ptr PackedBytes -> Ptr PackedBytes -> Ptr PackedBytes -> IO ()
|
sc_muladd :: Ptr PackedBytes -> Ptr PackedBytes -> Ptr PackedBytes -> Ptr PackedBytes -> IO ()
|
||||||
foreign import ccall unsafe "GFp_x25519_public_from_private"
|
foreign import ccall unsafe "GFp_x25519_public_from_private"
|
||||||
public_from_private :: Ptr PackedBytes -> Ptr PackedBytes -> IO ()
|
public_from_private :: Ptr PackedBytes -> Ptr PackedBytes -> IO ()
|
||||||
|
|||||||
5005
testdata/ed25519/fbv.test
vendored
5005
testdata/ed25519/fbv.test
vendored
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user