Pull to_bytes() into FieldElement.

This commit is contained in:
2019-05-21 19:45:08 -07:00
parent 8bca480e47
commit e6e3789127
3 changed files with 95 additions and 102 deletions

View File

@@ -76,6 +76,85 @@ impl FieldElement
h4 as i32, h5 as i32, h6 as i32, h7 as i32, h4 as i32, h5 as i32, h6 as i32, h7 as i32,
h8 as i32, h9 as i32] } h8 as i32, h9 as i32] }
} }
pub fn to_bytes(&self) -> Vec<u8>
{
let mut h0 = self.value[0];
let mut h1 = self.value[1];
let mut h2 = self.value[2];
let mut h3 = self.value[3];
let mut h4 = self.value[4];
let mut h5 = self.value[5];
let mut h6 = self.value[6];
let mut h7 = self.value[7];
let mut h8 = self.value[8];
let mut h9 = self.value[9];
let mut q = (19 * h9 + ((1i32) << 24)) >> 25;
q = (h0 + q) >> 26;
q = (h1 + q) >> 25;
q = (h2 + q) >> 26;
q = (h3 + q) >> 25;
q = (h4 + q) >> 26;
q = (h5 + q) >> 25;
q = (h6 + q) >> 26;
q = (h7 + q) >> 25;
q = (h8 + q) >> 26;
q = (h9 + q) >> 25;
/* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
h0 += 19 * q;
/* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
h1 += h0 >> 26; h0 &= KBOTTOM_26BITS as i32;
h2 += h1 >> 25; h1 &= KBOTTOM_25BITS as i32;
h3 += h2 >> 26; h2 &= KBOTTOM_26BITS as i32;
h4 += h3 >> 25; h3 &= KBOTTOM_25BITS as i32;
h5 += h4 >> 26; h4 &= KBOTTOM_26BITS as i32;
h6 += h5 >> 25; h5 &= KBOTTOM_25BITS as i32;
h7 += h6 >> 26; h6 &= KBOTTOM_26BITS as i32;
h8 += h7 >> 25; h7 &= KBOTTOM_25BITS as i32;
h9 += h8 >> 26; h8 &= KBOTTOM_26BITS as i32;
h9 &= KBOTTOM_25BITS as i32;
/* h10 = carry9 */
/* Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
* Have h0+...+2^230 h9 between 0 and 2^255-1;
* evidently 2^255 h10-2^255 q = 0.
* Goal: Output h0+...+2^230 h9. */
vec![ (h0 >> 0) as u8,
(h0 >> 8) as u8,
(h0 >> 16) as u8,
((h0 >> 24) | (((h1 as u32) << 2) as i32)) as u8,
(h1 >> 6) as u8,
(h1 >> 14) as u8,
((h1 >> 22) | (((h2 as u32) << 3) as i32)) as u8,
(h2 >> 5) as u8,
(h2 >> 13) as u8,
((h2 >> 21) | (((h3 as u32) << 5) as i32)) as u8,
(h3 >> 3) as u8,
(h3 >> 11) as u8,
((h3 >> 19) | (((h4 as u32) << 6) as i32)) as u8,
(h4 >> 2) as u8,
(h4 >> 10) as u8,
(h4 >> 18) as u8,
(h5 >> 0) as u8,
(h5 >> 8) as u8,
(h5 >> 16) as u8,
((h5 >> 24) | (((h6 as u32) << 1) as i32)) as u8,
(h6 >> 7) as u8,
(h6 >> 15) as u8,
((h6 >> 23) | (((h7 as u32) << 3) as i32)) as u8,
(h7 >> 5) as u8,
(h7 >> 13) as u8,
((h7 >> 21) | (((h8 as u32) << 4) as i32)) as u8,
(h8 >> 4) as u8,
(h8 >> 12) as u8,
((h8 >> 20) | (((h9 as u32) << 6) as i32)) as u8,
(h9 >> 2) as u8,
(h9 >> 10) as u8,
(h9 >> 18) as u8
]
}
} }
pub const KBOTTOM_25BITS : i64 = 0x1ffffffi64; pub const KBOTTOM_25BITS : i64 = 0x1ffffffi64;
@@ -111,85 +190,6 @@ fn loads() {
}); });
} }
pub fn fe_tobytes(s: &mut [u8], h: &FieldElement)
{
assert!(s.len() >= 32);
let mut h0 = h.value[0];
let mut h1 = h.value[1];
let mut h2 = h.value[2];
let mut h3 = h.value[3];
let mut h4 = h.value[4];
let mut h5 = h.value[5];
let mut h6 = h.value[6];
let mut h7 = h.value[7];
let mut h8 = h.value[8];
let mut h9 = h.value[9];
let mut q = (19 * h9 + ((1i32) << 24)) >> 25;
q = (h0 + q) >> 26;
q = (h1 + q) >> 25;
q = (h2 + q) >> 26;
q = (h3 + q) >> 25;
q = (h4 + q) >> 26;
q = (h5 + q) >> 25;
q = (h6 + q) >> 26;
q = (h7 + q) >> 25;
q = (h8 + q) >> 26;
q = (h9 + q) >> 25;
/* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
h0 += 19 * q;
/* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
h1 += h0 >> 26; h0 &= KBOTTOM_26BITS as i32;
h2 += h1 >> 25; h1 &= KBOTTOM_25BITS as i32;
h3 += h2 >> 26; h2 &= KBOTTOM_26BITS as i32;
h4 += h3 >> 25; h3 &= KBOTTOM_25BITS as i32;
h5 += h4 >> 26; h4 &= KBOTTOM_26BITS as i32;
h6 += h5 >> 25; h5 &= KBOTTOM_25BITS as i32;
h7 += h6 >> 26; h6 &= KBOTTOM_26BITS as i32;
h8 += h7 >> 25; h7 &= KBOTTOM_25BITS as i32;
h9 += h8 >> 26; h8 &= KBOTTOM_26BITS as i32;
h9 &= KBOTTOM_25BITS as i32;
/* h10 = carry9 */
/* Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
* Have h0+...+2^230 h9 between 0 and 2^255-1;
* evidently 2^255 h10-2^255 q = 0.
* Goal: Output h0+...+2^230 h9. */
s[0] = (h0 >> 0) as u8;
s[1] = (h0 >> 8) as u8;
s[2] = (h0 >> 16) as u8;
s[3] = ((h0 >> 24) | (((h1 as u32) << 2) as i32)) as u8;
s[4] = (h1 >> 6) as u8;
s[5] = (h1 >> 14) as u8;
s[6] = ((h1 >> 22) | (((h2 as u32) << 3) as i32)) as u8;
s[7] = (h2 >> 5) as u8;
s[8] = (h2 >> 13) as u8;
s[9] = ((h2 >> 21) | (((h3 as u32) << 5) as i32)) as u8;
s[10] = (h3 >> 3) as u8;
s[11] = (h3 >> 11) as u8;
s[12] = ((h3 >> 19) | (((h4 as u32) << 6) as i32)) as u8;
s[13] = (h4 >> 2) as u8;
s[14] = (h4 >> 10) as u8;
s[15] = (h4 >> 18) as u8;
s[16] = (h5 >> 0) as u8;
s[17] = (h5 >> 8) as u8;
s[18] = (h5 >> 16) as u8;
s[19] = ((h5 >> 24) | (((h6 as u32) << 1) as i32)) as u8;
s[20] = (h6 >> 7) as u8;
s[21] = (h6 >> 15) as u8;
s[22] = ((h6 >> 23) | (((h7 as u32) << 3) as i32)) as u8;
s[23] = (h7 >> 5) as u8;
s[24] = (h7 >> 13) as u8;
s[25] = ((h7 >> 21) | (((h8 as u32) << 4) as i32)) as u8;
s[26] = (h8 >> 4) as u8;
s[27] = (h8 >> 12) as u8;
s[28] = ((h8 >> 20) | (((h9 as u32) << 6) as i32)) as u8;
s[29] = (h9 >> 2) as u8;
s[30] = (h9 >> 10) as u8;
s[31] = (h9 >> 18) as u8;
}
#[cfg(test)] #[cfg(test)]
#[test] #[test]
fn from_to_bytes() { fn from_to_bytes() {
@@ -204,9 +204,8 @@ fn from_to_bytes() {
let mut cursor = Cursor::new(bbytes); let mut cursor = Cursor::new(bbytes);
cursor.read_i32_into::<NativeEndian>(&mut target.value).unwrap(); cursor.read_i32_into::<NativeEndian>(&mut target.value).unwrap();
assert_eq!(e, target, "from bytes"); assert_eq!(e, target, "from bytes");
let mut bytes = [0; 32]; let bytes = e.to_bytes();
fe_tobytes(&mut bytes, &e); assert_eq!(&bytes, abytes, "to bytes");
assert_eq!(&bytes.to_vec(), abytes, "to bytes");
}); });
} }
@@ -243,8 +242,7 @@ quickcheck! {
// this is somewhat self referential, given the definition of arbitrary, // this is somewhat self referential, given the definition of arbitrary,
// but more testing is more good // but more testing is more good
fn from_to_bytes_roundtrip(e: ValidFieldElement) -> bool { fn from_to_bytes_roundtrip(e: ValidFieldElement) -> bool {
let mut bytes = [0; 32]; let bytes = e.values.to_bytes();
fe_tobytes(&mut bytes, &e.values);
let trans = FieldElement::from_bytes(&bytes); let trans = FieldElement::from_bytes(&bytes);
trans == e.values trans == e.values
} }
@@ -822,9 +820,8 @@ fn cmov() {
pub fn fe_isnonzero(f: &FieldElement) -> bool pub fn fe_isnonzero(f: &FieldElement) -> bool
{ {
let mut s = [0; 32]; let s = f.to_bytes();
let mut res = false; let mut res = false;
fe_tobytes(&mut s, &f);
for i in 0..32 { for i in 0..32 {
res |= s[i] != 0; res |= s[i] != 0;
} }
@@ -833,8 +830,7 @@ pub fn fe_isnonzero(f: &FieldElement) -> bool
pub fn fe_isnegative(f: &FieldElement) -> bool pub fn fe_isnegative(f: &FieldElement) -> bool
{ {
let mut s = [0; 32]; let s = f.to_bytes();
fe_tobytes(&mut s, &f);
s[0] & 1 == 1 s[0] & 1 == 1
} }

View File

@@ -75,13 +75,12 @@ impl ED25519Private {
curve25519_scalar_mask(&mut result.private); curve25519_scalar_mask(&mut result.private);
let mut a = Point::new(); let mut a = Point::new();
x25519_ge_scalarmult_base(&mut a, &result.private); x25519_ge_scalarmult_base(&mut a, &result.private);
a.encode_to(&mut result.public); result.public.copy_from_slice(&a.encode());
result result
} }
pub fn sign(&self, msg: &[u8]) -> Vec<u8> pub fn sign(&self, msg: &[u8]) -> Vec<u8>
{ {
let mut signature_r = [0u8; 32];
let mut signature_s = [0u8; 32]; let mut signature_s = [0u8; 32];
let mut ctx = Sha512::new(); let mut ctx = Sha512::new();
@@ -95,7 +94,7 @@ impl ED25519Private {
println!("ME:r.y: {:?}", r.y); println!("ME:r.y: {:?}", r.y);
println!("ME:r.z: {:?}", r.z); println!("ME:r.z: {:?}", r.z);
println!("ME:r.t: {:?}", r.t); println!("ME:r.t: {:?}", r.t);
r.encode_to(&mut signature_r); let signature_r = r.encode();
println!("ME:signature_r: {:?}", signature_r); println!("ME:signature_r: {:?}", signature_r);
let hram_digest = eddsa_digest(&signature_r, &self.public, &msg); let hram_digest = eddsa_digest(&signature_r, &self.public, &msg);
let hram = digest_scalar(&hram_digest); let hram = digest_scalar(&hram_digest);
@@ -139,9 +138,8 @@ impl ED25519Public {
let h = digest_scalar(&h_digest); let h = digest_scalar(&h_digest);
let mut r = Point2::new(); let mut r = Point2::new();
ge_double_scalarmult_vartime(&mut r, &h, &a, &signature_s); ge_double_scalarmult_vartime(&mut r, &h, &a, &signature_s);
let mut r_check = [0; 32]; let r_check = r.encode();
r.encode_to(&mut r_check); signature_r.to_vec() == r_check
signature_r == r_check
} }
} }

View File

@@ -95,9 +95,9 @@ impl Point {
return Some(Point{ x: hx, y: hy, z: hz, t: ht }); return Some(Point{ x: hx, y: hy, z: hz, t: ht });
} }
pub fn encode_to(&self, target: &mut [u8]) pub fn encode(&self) -> Vec<u8>
{ {
into_encoded_point(target, &self.x, &self.y, &self.z); into_encoded_point(&self.x, &self.y, &self.z)
} }
pub fn invert(&mut self) pub fn invert(&mut self)
@@ -173,9 +173,9 @@ impl Point2 {
} }
} }
pub fn encode_to(&self, target: &mut [u8]) pub fn encode(&self) -> Vec<u8>
{ {
into_encoded_point(target, &self.x, &self.y, &self.z); into_encoded_point(&self.x, &self.y, &self.z)
} }
} }
@@ -1840,19 +1840,18 @@ pub fn curve25519_scalar_mask(a: &mut [u8])
// }); // });
//} //}
// //
fn into_encoded_point(bytes: &mut [u8], x: &FieldElement, y: &FieldElement, z: &FieldElement) fn into_encoded_point(x: &FieldElement, y: &FieldElement, z: &FieldElement) -> Vec<u8>
{ {
let mut x_over_z = FieldElement::new(); let mut x_over_z = FieldElement::new();
let mut y_over_z = FieldElement::new(); let mut y_over_z = FieldElement::new();
assert!(bytes.len() >= 32);
let recip = fe_invert(z); let recip = fe_invert(z);
fe_mul(&mut x_over_z, x, &recip); fe_mul(&mut x_over_z, x, &recip);
fe_mul(&mut y_over_z, y, &recip); fe_mul(&mut y_over_z, y, &recip);
fe_tobytes(bytes, &y_over_z); let mut bytes = y_over_z.to_bytes();
let sign_bit = if fe_isnegative(&x_over_z) { 1 } else { 0 }; let sign_bit = if fe_isnegative(&x_over_z) { 1 } else { 0 };
// The preceding computations must execute in constant time, but this // The preceding computations must execute in constant time, but this
// doesn't need to. // doesn't need to.
bytes[31] ^= sign_bit << 7; bytes[31] ^= sign_bit << 7;
bytes
} }