mirror of
https://github.com/saymrwulf/risc0-curve25519-dalek-source.git
synced 2026-09-04 20:03:40 +00:00
Initial commit.
This commit is contained in:
commit
387a56fe2c
9 changed files with 4406 additions and 0 deletions
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
target
|
||||
Cargo.lock
|
||||
|
||||
*~
|
||||
\#*
|
||||
.\#*
|
||||
*.swp
|
||||
*.orig
|
||||
*.bak
|
||||
|
||||
*.s
|
||||
69
Cargo.toml
Normal file
69
Cargo.toml
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
[package]
|
||||
name = "curve25519-dalek"
|
||||
version = "0.1.0"
|
||||
authors = ["Isis Lovecruft <isis@patternsinthevoid.net>",
|
||||
"Henry de Valence <hdevalence@hdevalence.ca>"]
|
||||
readme = "README.md"
|
||||
license-file = "LICENSE"
|
||||
repository = "https://code.ciph.re/isis/curve25519-dalek"
|
||||
homepage = "https://code.ciph.re/isis/curve25519-dalek"
|
||||
documentation = "https://docs.rs/curve25519-dalek"
|
||||
keywords = ["cryptography", "curve25519", "elliptic", "curve", "ECC"]
|
||||
description = "A low-level cryptographic library for point, group, field, and scalar operations on a curve isomorphic to the twisted Edwards curve defined by x²+y² = 121665/121666 x²y² over GF(2²⁵⁵ - 19)."
|
||||
exclude = [
|
||||
".gitignore"
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
arrayref = "0.3.2"
|
||||
|
||||
# The development profile, used for `cargo build`.
|
||||
[profile.dev]
|
||||
opt-level = 0 # controls the `--opt-level` the compiler builds with
|
||||
debug = true # controls whether the compiler passes `-g`
|
||||
rpath = false # controls whether the compiler passes `-C rpath`
|
||||
lto = false # controls `-C lto` for binaries and staticlibs
|
||||
debug-assertions = true # controls whether debug assertions are enabled
|
||||
codegen-units = 1 # controls whether the compiler passes `-C codegen-units`
|
||||
# `codegen-units` is ignored when `lto = true`
|
||||
panic = 'unwind' # panic strategy (`-C panic=...`), can also be 'abort'
|
||||
|
||||
# The release profile, used for `cargo build --release`.
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
debug = false
|
||||
rpath = false
|
||||
lto = false
|
||||
debug-assertions = false
|
||||
codegen-units = 1
|
||||
panic = 'unwind'
|
||||
|
||||
# The testing profile, used for `cargo test`.
|
||||
[profile.test]
|
||||
opt-level = 0
|
||||
debug = true
|
||||
rpath = false
|
||||
lto = false
|
||||
debug-assertions = true
|
||||
codegen-units = 1
|
||||
panic = 'unwind'
|
||||
|
||||
# The benchmarking profile, used for `cargo bench`.
|
||||
[profile.bench]
|
||||
opt-level = 3
|
||||
debug = false
|
||||
rpath = false
|
||||
lto = false
|
||||
debug-assertions = false
|
||||
codegen-units = 1
|
||||
panic = 'unwind'
|
||||
|
||||
# The documentation profile, used for `cargo doc`.
|
||||
[profile.doc]
|
||||
opt-level = 0
|
||||
debug = true
|
||||
rpath = false
|
||||
lto = false
|
||||
debug-assertions = true
|
||||
codegen-units = 1
|
||||
panic = 'unwind'
|
||||
129
LICENSE
Normal file
129
LICENSE
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
To the extent possible under law, the author(s) have waived all copyright and related or
|
||||
neighboring rights to curve25519-dalek, using the Creative Commons "CC0" public domain dedication.
|
||||
|
||||
|
||||
|
||||
Creative Commons CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
|
||||
SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT
|
||||
RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS"
|
||||
BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT
|
||||
OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR
|
||||
DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
purpose of contributing to a commons of creative, cultural and scientific
|
||||
works ("Commons") that the public can reliably and without fear of later
|
||||
claims of infringement build upon, modify, incorporate in other works, reuse
|
||||
and redistribute as freely as possible in any form whatsoever and for any
|
||||
purposes, including without limitation commercial purposes. These owners may
|
||||
contribute to the Commons to promote the ideal of a free culture and the
|
||||
further production of creative, cultural and scientific works, or to gain
|
||||
reputation or greater distribution for their Work in part through the use and
|
||||
efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation
|
||||
of additional consideration or compensation, the person associating CC0 with a
|
||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||
and publicly distribute the Work under its terms, with knowledge of his or her
|
||||
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||
effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not limited
|
||||
to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation thereof,
|
||||
including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world
|
||||
based on applicable law or treaty, and any national implementations
|
||||
thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||
and Related Rights and associated claims and causes of action, whether now
|
||||
known or unknown (including existing as well as future claims and causes of
|
||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number of
|
||||
copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
||||
the Waiver for the benefit of each member of the public at large and to the
|
||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
||||
shall not be subject to revocation, rescission, cancellation, termination, or
|
||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
||||
by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
shall be preserved to the maximum extent permitted taking into account
|
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
||||
non transferable, non sublicensable, non exclusive, irrevocable and
|
||||
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
||||
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
||||
provided by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and (iv) for any
|
||||
purpose whatsoever, including without limitation commercial, advertising or
|
||||
promotional purposes (the "License"). The License shall be deemed effective as
|
||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
||||
License for any reason be judged legally invalid or ineffective under
|
||||
applicable law, such partial invalidity or ineffectiveness shall not
|
||||
invalidate the remainder of the License, and in such case Affirmer hereby
|
||||
affirms that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
||||
and causes of action with respect to the Work, in either case contrary to
|
||||
Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied, statutory
|
||||
or otherwise, including without limitation warranties of title,
|
||||
merchantability, fitness for a particular purpose, non infringement, or
|
||||
the absence of latent or other defects, accuracy, or the present or
|
||||
absence of errors, whether or not discoverable, all to the greatest
|
||||
extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the
|
||||
Work. Further, Affirmer disclaims responsibility for obtaining any
|
||||
necessary consents, permissions or other rights required for any use of
|
||||
the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
||||
28
README.md
Normal file
28
README.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
# curve25519-dalek [](https://docs.rs/curve25519-dalek/badge.svg)
|
||||
|
||||
*A low-level cryptographic library for point, group, field, and scalar
|
||||
operations on a curve isomorphic to the twisted Edwards curve defined by x²+y²
|
||||
= 121665/121666 x²y² over GF(2²⁵⁵ - 19).*
|
||||
|
||||
*SPOILER ALERT:* **The Twelfth Doctor's first encounter with the Daleks is in
|
||||
his second full episode, "Into the Dalek". A beleaguered ship of the "Combined
|
||||
Galactic Resistance" has discovered a broken Dalek that has turned "good",
|
||||
desiring to kill all other Daleks. The Doctor, Clara and a team of soldiers
|
||||
are miniaturized and enter the Dalek, which the Doctor names Rusty. They
|
||||
repair the damage, but accidentally restore it to its original nature, causing
|
||||
it to go on the rampage and alert the Dalek fleet to the whereabouts of the
|
||||
rebel ship. However, the Doctor manages to return Rusty to its previous state
|
||||
by linking his mind with the Dalek's: Rusty shares the Doctor's view of the
|
||||
universe's beauty, but also his deep hatred of the Daleks. Rusty destroys the
|
||||
other Daleks and departs the ship, determined to track down and bring an end
|
||||
to the Dalek race.**
|
||||
|
||||
Significant portions of this code are ported from
|
||||
[Adam Langley's Golang ed25519 library](https://github.com/agl/ed25519), along
|
||||
with referencing the ref10 implementation.
|
||||
|
||||
## TODO
|
||||
|
||||
* Implement hashing to a point on the curve.
|
||||
* Maybe implement Mike Hamburg's Decaf point compression format.
|
||||
1121
src/curve.rs
Normal file
1121
src/curve.rs
Normal file
File diff suppressed because it is too large
Load diff
972
src/field.rs
Normal file
972
src/field.rs
Normal file
|
|
@ -0,0 +1,972 @@
|
|||
// -*- mode: rust; coding: utf-8; -*-
|
||||
//
|
||||
// To the extent possible under law, the authors have waived all
|
||||
// copyright and related or neighboring rights to curve25519-dalek,
|
||||
// using the Creative Commons "CC0" public domain dedication. See
|
||||
// <http://creativecommons.org/publicdomain/zero/.0/> for full
|
||||
// details.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! Field arithmetic for ℤ/(2²⁵⁵-19).
|
||||
//!
|
||||
//! Based on Adam Langley's curve25519-donna and (Golang) ed25519
|
||||
//! implementations.
|
||||
|
||||
use std::clone::Clone;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::{Add, AddAssign};
|
||||
use std::ops::{Sub, SubAssign};
|
||||
use std::ops::{Mul, MulAssign};
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::cmp::{Eq, PartialEq};
|
||||
use std::ops::Neg;
|
||||
|
||||
use util::byte_is_nonzero;
|
||||
|
||||
/// FieldElements are represented as an array of ten "Limbs", which are radix
|
||||
/// 25.5, that is, each Limb of a FieldElement alternates between being
|
||||
/// represented as a factor of 2^25 or 2^26 more than the last corresponding
|
||||
/// integer.
|
||||
pub type Limb = i32;
|
||||
|
||||
/// FieldElement represents an element of the field GF(2^255 - 19). An element
|
||||
/// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
|
||||
/// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
|
||||
/// context.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct FieldElement(pub [Limb; 10]);
|
||||
|
||||
impl PartialEq for FieldElement {
|
||||
/// Test equality between two FieldElements by converting them to bytes.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This comparison is *not* constant time. It could easily be
|
||||
/// made to be, but the main use of an `Eq` implementation is for
|
||||
/// branching, so it seems pointless.
|
||||
///
|
||||
/// XXX it would be good to encode constant-time considerations
|
||||
/// (no data flow from secret information) into Rust's type
|
||||
/// system.
|
||||
fn eq(&self, other: &FieldElement) -> bool {
|
||||
let self_bytes = self.to_bytes();
|
||||
let other_bytes = other.to_bytes();
|
||||
let mut are_equal: bool = true;
|
||||
for i in 0..32 {
|
||||
are_equal &= self_bytes[i] == other_bytes[i];
|
||||
}
|
||||
return are_equal;
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for FieldElement {}
|
||||
|
||||
impl Debug for FieldElement {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
write!(f, "FieldElement: {:?}", &self.0[..])
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for FieldElement {
|
||||
type Output = Limb;
|
||||
|
||||
fn index<'a>(&'a self, _index: usize) -> &'a Limb {
|
||||
let ret: &'a Limb = &(self.0[_index]);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for FieldElement {
|
||||
fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut Limb {
|
||||
let ret: &'a mut Limb = &mut(self.0[_index]);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> AddAssign<&'b FieldElement> for FieldElement {
|
||||
fn add_assign(&mut self, _rhs: &'b FieldElement) { // fsum()
|
||||
for i in 0..10 {
|
||||
self[i] += _rhs[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Add<&'b FieldElement> for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
fn add(self, _rhs: &'b FieldElement) -> FieldElement {
|
||||
let mut output = self.clone();
|
||||
output += _rhs;
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> SubAssign<&'b FieldElement> for FieldElement {
|
||||
fn sub_assign(&mut self, _rhs: &'b FieldElement) { // fdifference()
|
||||
for i in 0..10 {
|
||||
self[i] -= _rhs[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Sub<&'b FieldElement> for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
fn sub(self, _rhs: &'b FieldElement) -> FieldElement {
|
||||
let mut output = self.clone();
|
||||
output -= _rhs;
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b> MulAssign<&'b FieldElement> for FieldElement {
|
||||
fn mul_assign(&mut self, _rhs: &'b FieldElement) {
|
||||
self.0 = self.multiply(_rhs).0;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Mul<&'b FieldElement> for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
fn mul(self, _rhs: &'b FieldElement) -> FieldElement {
|
||||
self.multiply(_rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a FieldElement {
|
||||
type Output = FieldElement;
|
||||
fn neg(self) -> FieldElement {
|
||||
let mut output = self.clone();
|
||||
output.negate();
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert an array of (at least) three bytes into an i64.
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub fn load3(input: &[u8]) -> i64 {
|
||||
(input[0] as i64)
|
||||
| ((input[1] as i64) << 8)
|
||||
| ((input[2] as i64) << 16)
|
||||
}
|
||||
|
||||
/// Convert an array of (at least) four bytes into an i64.
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub fn load4(input: &[u8]) -> i64 {
|
||||
(input[0] as i64)
|
||||
| ((input[1] as i64) << 8)
|
||||
| ((input[2] as i64) << 16)
|
||||
| ((input[3] as i64) << 24)
|
||||
}
|
||||
|
||||
impl FieldElement {
|
||||
/// Invert the sign of this field element
|
||||
pub fn negate(&mut self) {
|
||||
for i in 0..10 {
|
||||
self[i] = -self[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct the additive identity
|
||||
pub fn zero() -> FieldElement {
|
||||
FieldElement([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ])
|
||||
}
|
||||
|
||||
/// Construct the multiplicative identity
|
||||
pub fn one() -> FieldElement {
|
||||
FieldElement([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ])
|
||||
}
|
||||
|
||||
/// Overwrite this FieldElement with one of the inputs without branching.
|
||||
/// Like `conditional_assign`, but chooses between two inputs instead of
|
||||
/// one input and the original value.
|
||||
///
|
||||
/// If `choice == 0`, replace `self` with `f`:
|
||||
///
|
||||
/// ```
|
||||
/// # use curve25519_dalek::field::FieldElement;
|
||||
/// let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
|
||||
/// let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
|
||||
/// let mut h = FieldElement([0,0,0,0,0,0,0,0,0,0]);
|
||||
/// h.conditional_choose(&f, &g, 0);
|
||||
/// assert!(h == f);
|
||||
/// ```
|
||||
///
|
||||
/// If `choice == 1`, replace `self` with `g`:
|
||||
///
|
||||
/// ```
|
||||
/// # use curve25519_dalek::field::FieldElement;
|
||||
/// # let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
|
||||
/// # let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
|
||||
/// # let mut h = FieldElement([0,0,0,0,0,0,0,0,0,0]);
|
||||
/// h.conditional_choose(&f, &g, 1);
|
||||
/// assert!(h == g);
|
||||
/// ```
|
||||
///
|
||||
/// # Preconditions
|
||||
///
|
||||
/// * `b` in {0,1}
|
||||
pub fn conditional_choose(&mut self,
|
||||
f: &FieldElement,
|
||||
g: &FieldElement,
|
||||
choice: u8)
|
||||
{
|
||||
let mask = -(choice as Limb);
|
||||
for i in 0..10 {
|
||||
self[i] = f[i] ^ (mask & (f[i] ^ g[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/// Conditionally assign the Limbs of another FieldElement to this
|
||||
/// one. Like `conditional_choose`, but choosing between one
|
||||
/// input and the original value.
|
||||
///
|
||||
/// If `choice == 0`, replace `self` with `self`:
|
||||
///
|
||||
/// ```
|
||||
/// # use curve25519_dalek::field::FieldElement;
|
||||
/// let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
|
||||
/// let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
|
||||
/// let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]);
|
||||
/// h.conditional_assign(&g, 0);
|
||||
/// assert!(h == f);
|
||||
/// ```
|
||||
///
|
||||
/// If `choice == 1`, replace `self` with `f`:
|
||||
///
|
||||
/// ```
|
||||
/// # use curve25519_dalek::field::FieldElement;
|
||||
/// # let f = FieldElement([1,1,1,1,1,1,1,1,1,1]);
|
||||
/// # let g = FieldElement([2,2,2,2,2,2,2,2,2,2]);
|
||||
/// # let mut h = FieldElement([1,1,1,1,1,1,1,1,1,1]);
|
||||
/// h.conditional_assign(&g, 1);
|
||||
/// assert!(h == g);
|
||||
/// ```
|
||||
///
|
||||
/// # Preconditions
|
||||
///
|
||||
/// * `choice` in {0,1}
|
||||
pub fn conditional_assign(&mut self, f: &FieldElement, choice: u8) {
|
||||
let mask = -(choice as Limb);
|
||||
for i in 0..10 {
|
||||
self[i] ^= mask & (self[i] ^ f[i]);
|
||||
}
|
||||
}
|
||||
|
||||
fn combine_coeffs(input: &[i64;10]) -> FieldElement { //FeCombine
|
||||
let mut c = [0i64;10];
|
||||
let mut h = input.clone();
|
||||
|
||||
/*
|
||||
|h[0]| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
|
||||
i.e. |h[0]| <= 1.2*2^59; narrower ranges for h[2], h[4], h[6], h[8]
|
||||
|h[1]| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
|
||||
i.e. |h[1]| <= 1.5*2^58; narrower ranges for h[3], h[5], h[7], h[9]
|
||||
*/
|
||||
|
||||
c[0] = (h[0] + (1 << 25)) >> 26;
|
||||
h[1] += c[0];
|
||||
h[0] -= c[0] << 26;
|
||||
c[4] = (h[4] + (1 << 25)) >> 26;
|
||||
h[5] += c[4];
|
||||
h[4] -= c[4] << 26;
|
||||
/* |h[0]| <= 2^25 */
|
||||
/* |h[4]| <= 2^25 */
|
||||
/* |h[1]| <= 1.51*2^58 */
|
||||
/* |h[5]| <= 1.51*2^58 */
|
||||
|
||||
c[1] = (h[1] + (1 << 24)) >> 25;
|
||||
h[2] += c[1];
|
||||
h[1] -= c[1] << 25;
|
||||
c[5] = (h[5] + (1 << 24)) >> 25;
|
||||
h[6] += c[5];
|
||||
h[5] -= c[5] << 25;
|
||||
/* |h[1]| <= 2^24; from now on fits into int32 */
|
||||
/* |h[5]| <= 2^24; from now on fits into int32 */
|
||||
/* |h[2]| <= 1.21*2^59 */
|
||||
/* |h[6]| <= 1.21*2^59 */
|
||||
|
||||
c[2] = (h[2] + (1 << 25)) >> 26;
|
||||
h[3] += c[2];
|
||||
h[2] -= c[2] << 26;
|
||||
c[6] = (h[6] + (1 << 25)) >> 26;
|
||||
h[7] += c[6];
|
||||
h[6] -= c[6] << 26;
|
||||
/* |h[2]| <= 2^25; from now on fits into int32 unchanged */
|
||||
/* |h[6]| <= 2^25; from now on fits into int32 unchanged */
|
||||
/* |h[3]| <= 1.51*2^58 */
|
||||
/* |h[7]| <= 1.51*2^58 */
|
||||
|
||||
c[3] = (h[3] + (1 << 24)) >> 25;
|
||||
h[4] += c[3];
|
||||
h[3] -= c[3] << 25;
|
||||
c[7] = (h[7] + (1 << 24)) >> 25;
|
||||
h[8] += c[7];
|
||||
h[7] -= c[7] << 25;
|
||||
/* |h[3]| <= 2^24; from now on fits into int32 unchanged */
|
||||
/* |h[7]| <= 2^24; from now on fits into int32 unchanged */
|
||||
/* |h[4]| <= 1.52*2^33 */
|
||||
/* |h[8]| <= 1.52*2^33 */
|
||||
|
||||
c[4] = (h[4] + (1 << 25)) >> 26;
|
||||
h[5] += c[4];
|
||||
h[4] -= c[4] << 26;
|
||||
c[8] = (h[8] + (1 << 25)) >> 26;
|
||||
h[9] += c[8];
|
||||
h[8] -= c[8] << 26;
|
||||
/* |h[4]| <= 2^25; from now on fits into int32 unchanged */
|
||||
/* |h[8]| <= 2^25; from now on fits into int32 unchanged */
|
||||
/* |h[5]| <= 1.01*2^24 */
|
||||
/* |h[9]| <= 1.51*2^58 */
|
||||
|
||||
c[9] = (h[9] + (1 << 24)) >> 25;
|
||||
h[0] += c[9] * 19;
|
||||
h[9] -= c[9] << 25;
|
||||
/* |h[9]| <= 2^24; from now on fits into int32 unchanged */
|
||||
/* |h[0]| <= 1.8*2^37 */
|
||||
|
||||
c[0] = (h[0] + (1 << 25)) >> 26;
|
||||
h[1] += c[0];
|
||||
h[0] -= c[0] << 26;
|
||||
/* |h[0]| <= 2^25; from now on fits into int32 unchanged */
|
||||
/* |h[1]| <= 1.01*2^24 */
|
||||
|
||||
let mut output = FieldElement([0i32;10]);
|
||||
output[0] = h[0] as i32;
|
||||
output[1] = h[1] as i32;
|
||||
output[2] = h[2] as i32;
|
||||
output[3] = h[3] as i32;
|
||||
output[4] = h[4] as i32;
|
||||
output[5] = h[5] as i32;
|
||||
output[6] = h[6] as i32;
|
||||
output[7] = h[7] as i32;
|
||||
output[8] = h[8] as i32;
|
||||
output[9] = h[9] as i32;
|
||||
output
|
||||
}
|
||||
|
||||
/// Create a FieldElement by demarshalling an array of 32 bytes.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use curve25519_dalek::field::FieldElement;
|
||||
/// let data: [u8; 32] = [ 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
/// 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
/// 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
/// 25, 26, 27, 28, 29, 30, 31, 32 ];
|
||||
/// let fe: FieldElement = FieldElement::from_bytes(&data);
|
||||
/// assert_eq!(fe,
|
||||
/// FieldElement([ 197121, -4095679, 21045505, 6840408, 4209720,
|
||||
/// 1249809, -7665014, -12377341, 30523826, 8420472]))
|
||||
/// ```
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// Returns a new FieldElement.
|
||||
pub fn from_bytes(data: &[u8;32]) -> FieldElement { //FeFromBytes
|
||||
let mut h = [0i64;10];
|
||||
h[0] = load4(&data[ 0..]);
|
||||
h[1] = load3(&data[ 4..]) << 6;
|
||||
h[2] = load3(&data[ 7..]) << 5;
|
||||
h[3] = load3(&data[10..]) << 3;
|
||||
h[4] = load3(&data[13..]) << 2;
|
||||
h[5] = load4(&data[16..]);
|
||||
h[6] = load3(&data[20..]) << 7;
|
||||
h[7] = load3(&data[23..]) << 5;
|
||||
h[8] = load3(&data[26..]) << 4;
|
||||
h[9] = (load3(&data[29..]) & 8388607) << 2;
|
||||
|
||||
FieldElement::combine_coeffs(&h)
|
||||
}
|
||||
|
||||
/// Marshal this FieldElement into a 32-byte array.
|
||||
///
|
||||
/// # Preconditions
|
||||
///
|
||||
/// * `|h[i]|` bounded by 1.1*2^25, 1.1*2^24, 1.1*2^25, 1.1*2^24, etc.
|
||||
///
|
||||
/// # Lemma
|
||||
///
|
||||
/// Write p = 2^255 - 19 and q = floor(h/p).
|
||||
///
|
||||
/// Basic claim: q = floor(2^(-255)(h + 19 * 2^-25 h9 + 2^-1)).
|
||||
///
|
||||
/// # Proof
|
||||
///
|
||||
/// Have |h|<=p so |q|<=1 so |19^2 * 2^-255 * q| < 1/4.
|
||||
///
|
||||
/// Also have |h-2^230 * h9| < 2^230 so |19 * 2^-255 * (h-2^230 * h9)| < 1/4.
|
||||
///
|
||||
/// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9), then 0<y<1.
|
||||
///
|
||||
/// Write r = h - pq.
|
||||
///
|
||||
/// Have 0 <= r< = p-1 = 2^255 - 20.
|
||||
///
|
||||
/// Thus 0 <= r + 19 * 2^-255 * r < r + 19 * 2^-255 * 2^255 <= 2^255 - 1.
|
||||
///
|
||||
/// Write x = r + 19 * 2^-255 * r + y.
|
||||
///
|
||||
/// Then 0 < x < 2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
|
||||
///
|
||||
/// Have q+2^(-255)x = 2^-255 * (h + 19 * 2^-25 * h9 + 2^-1),
|
||||
/// so floor(2^-255 * (h + 19 * 2^-25 * h9 + 2^-1)) = q.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Continuing from the previous example in `FieldElement::from_bytes`:
|
||||
///
|
||||
/// ```
|
||||
/// # use curve25519_dalek::field::FieldElement;
|
||||
/// let data: [u8; 32] = [ 1, 2, 3, 4, 5, 6, 7, 8,
|
||||
/// 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
/// 17, 18, 19, 20, 21, 22, 23, 24,
|
||||
/// 25, 26, 27, 28, 29, 30, 31, 32 ];
|
||||
/// let fe: FieldElement = FieldElement([ 197121, -4095679, 21045505, 6840408, 4209720,
|
||||
/// 1249809, -7665014, -12377341, 30523826, 8420472]);
|
||||
/// let bytes: [u8; 32] = fe.to_bytes();
|
||||
/// assert!(data == bytes);
|
||||
/// ```
|
||||
pub fn to_bytes(&self) -> [u8;32] { //FeToBytes
|
||||
let mut carry = [0i32; 10];
|
||||
let mut h = self.clone();
|
||||
|
||||
let mut q:i32 = (19*h[9] + (1 << 24)) >> 25;
|
||||
q = (h[0] + q) >> 26;
|
||||
q = (h[1] + q) >> 25;
|
||||
q = (h[2] + q) >> 26;
|
||||
q = (h[3] + q) >> 25;
|
||||
q = (h[4] + q) >> 26;
|
||||
q = (h[5] + q) >> 25;
|
||||
q = (h[6] + q) >> 26;
|
||||
q = (h[7] + q) >> 25;
|
||||
q = (h[8] + q) >> 26;
|
||||
q = (h[9] + q) >> 25;
|
||||
|
||||
// Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
|
||||
h[0] += 19 * q;
|
||||
// Goal: Output h-2^255 q, which is between 0 and 2^255-20.
|
||||
|
||||
carry[0] = h[0] >> 26;
|
||||
h[1] += carry[0];
|
||||
h[0] -= carry[0] << 26;
|
||||
carry[1] = h[1] >> 25;
|
||||
h[2] += carry[1];
|
||||
h[1] -= carry[1] << 25;
|
||||
carry[2] = h[2] >> 26;
|
||||
h[3] += carry[2];
|
||||
h[2] -= carry[2] << 26;
|
||||
carry[3] = h[3] >> 25;
|
||||
h[4] += carry[3];
|
||||
h[3] -= carry[3] << 25;
|
||||
carry[4] = h[4] >> 26;
|
||||
h[5] += carry[4];
|
||||
h[4] -= carry[4] << 26;
|
||||
carry[5] = h[5] >> 25;
|
||||
h[6] += carry[5];
|
||||
h[5] -= carry[5] << 25;
|
||||
carry[6] = h[6] >> 26;
|
||||
h[7] += carry[6];
|
||||
h[6] -= carry[6] << 26;
|
||||
carry[7] = h[7] >> 25;
|
||||
h[8] += carry[7];
|
||||
h[7] -= carry[7] << 25;
|
||||
carry[8] = h[8] >> 26;
|
||||
h[9] += carry[8];
|
||||
h[8] -= carry[8] << 26;
|
||||
carry[9] = h[9] >> 25;
|
||||
h[9] -= carry[9] << 25;
|
||||
// h10 = carry9
|
||||
|
||||
// Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
|
||||
// Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
|
||||
// evidently 2^255 h10-2^255 q = 0.
|
||||
// Goal: Output h[0]+...+2^230 h[9].
|
||||
|
||||
let mut s = [0u8;32];
|
||||
s[0] = (h[0] >> 0) as u8;
|
||||
s[1] = (h[0] >> 8) as u8;
|
||||
s[2] = (h[0] >> 16) as u8;
|
||||
s[3] = ((h[0] >> 24) | (h[1] << 2)) as u8;
|
||||
s[4] = (h[1] >> 6) as u8;
|
||||
s[5] = (h[1] >> 14) as u8;
|
||||
s[6] = ((h[1] >> 22) | (h[2] << 3)) as u8;
|
||||
s[7] = (h[2] >> 5) as u8;
|
||||
s[8] = (h[2] >> 13) as u8;
|
||||
s[9] = ((h[2] >> 21) | (h[3] << 5)) as u8;
|
||||
s[10] = (h[3] >> 3) as u8;
|
||||
s[11] = (h[3] >> 11) as u8;
|
||||
s[12] = ((h[3] >> 19) | (h[4] << 6)) as u8;
|
||||
s[13] = (h[4] >> 2) as u8;
|
||||
s[14] = (h[4] >> 10) as u8;
|
||||
s[15] = (h[4] >> 18) as u8;
|
||||
s[16] = (h[5] >> 0) as u8;
|
||||
s[17] = (h[5] >> 8) as u8;
|
||||
s[18] = (h[5] >> 16) as u8;
|
||||
s[19] = ((h[5] >> 24) | (h[6] << 1)) as u8;
|
||||
s[20] = (h[6] >> 7) as u8;
|
||||
s[21] = (h[6] >> 15) as u8;
|
||||
s[22] = ((h[6] >> 23) | (h[7] << 3)) as u8;
|
||||
s[23] = (h[7] >> 5) as u8;
|
||||
s[24] = (h[7] >> 13) as u8;
|
||||
s[25] = ((h[7] >> 21) | (h[8] << 4)) as u8;
|
||||
s[26] = (h[8] >> 4) as u8;
|
||||
s[27] = (h[8] >> 12) as u8;
|
||||
s[28] = ((h[8] >> 20) | (h[9] << 6)) as u8;
|
||||
s[29] = (h[9] >> 2) as u8;
|
||||
s[30] = (h[9] >> 10) as u8;
|
||||
s[31] = (h[9] >> 18) as u8;
|
||||
|
||||
//Clear high bit
|
||||
s[31] &= 127u8;
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
/// XXX clarify documentation
|
||||
/// Determine if this field element, represented as a byte array,
|
||||
/// is less than or equal to another field element represented as
|
||||
/// a byte array.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Returns `1u8` if `self.to_bytes() <= other.to_bytes()`, and `0u8` otherwise.
|
||||
pub fn bytes_equal_less_than(&self, other: &[u8; 32]) -> u8 { // feBytesLess
|
||||
// XXX cleanup
|
||||
let mut equal_so_far: i32 = -1i32;
|
||||
let mut greater: i32 = 0i32;
|
||||
|
||||
let this: [u8; 32] = self.to_bytes();
|
||||
|
||||
for i in 32 .. 0 {
|
||||
let x: i32 = this[i-1] as i32;
|
||||
let y: i32 = other[i-1] as i32;
|
||||
|
||||
greater = (!equal_so_far & greater) | (equal_so_far & ((x - y) >> 31));
|
||||
equal_so_far = equal_so_far & (((x ^ y) - 1) >> 31);
|
||||
}
|
||||
|
||||
(!equal_so_far & 1 & greater) as u8
|
||||
}
|
||||
|
||||
/// Determine if this `FieldElement` is negative.
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// If negative, return `1i32`. Otherwise, return `0i32`.
|
||||
// XXX should return u8
|
||||
pub fn is_negative(&self) -> i32 { //FeIsNegative
|
||||
let bytes = self.to_bytes();
|
||||
(bytes[0] & 1) as i32
|
||||
}
|
||||
|
||||
/// Determine if this `FieldElement` is non-zero.
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// If non-zero, return `1u8`. Otherwise, return `0u8`.
|
||||
pub fn is_nonzero(&self) -> u8 { //FeIsNonZero
|
||||
let bytes = self.to_bytes();
|
||||
let mut x = 0u8;
|
||||
for b in &bytes {
|
||||
x |= *b;
|
||||
}
|
||||
return byte_is_nonzero(x);
|
||||
}
|
||||
|
||||
/// Calculates h = f * g. Can overlap h with f or g.
|
||||
///
|
||||
/// # Preconditions
|
||||
///
|
||||
/// * |f[i]| bounded by 1.1*2^26, 1.1*2^25, 1.1*2^26, 1.1*2^25, etc.
|
||||
/// * |g[i]| bounded by 1.1*2^26, 1.1*2^25, 1.1*2^26, 1.1*2^25, etc.
|
||||
///
|
||||
/// # Postconditions
|
||||
///
|
||||
/// * |h| bounded by 1.1*2^25, 1.1*2^24, 1.1*2^25, 1.1*2^24, etc.
|
||||
///
|
||||
/// ## Notes on implementation strategy
|
||||
///
|
||||
/// * Using schoolbook multiplication.
|
||||
/// * Karatsuba would save a little in some cost models.
|
||||
///
|
||||
/// * Most multiplications by 2 and 19 are 32-bit precomputations;
|
||||
/// cheaper than 64-bit postcomputations.
|
||||
///
|
||||
/// * There is one remaining multiplication by 19 in the carry chain;
|
||||
/// one *19 precomputation can be merged into this,
|
||||
/// but the resulting data flow is considerably less clean.
|
||||
///
|
||||
/// * There are 12 carries below.
|
||||
/// 10 of them are 2-way parallelizable and vectorizable.
|
||||
/// Can get away with 11 carries, but then data flow is much deeper.
|
||||
///
|
||||
/// * With tighter constraints on inputs can squeeze carries into int32.
|
||||
pub fn multiply(&self, _rhs: &FieldElement) -> FieldElement {
|
||||
let f0 = self[0] as i64;
|
||||
let f1 = self[1] as i64;
|
||||
let f2 = self[2] as i64;
|
||||
let f3 = self[3] as i64;
|
||||
let f4 = self[4] as i64;
|
||||
let f5 = self[5] as i64;
|
||||
let f6 = self[6] as i64;
|
||||
let f7 = self[7] as i64;
|
||||
let f8 = self[8] as i64;
|
||||
let f9 = self[9] as i64;
|
||||
|
||||
let f1_2 = (2 * self[1]) as i64;
|
||||
let f3_2 = (2 * self[3]) as i64;
|
||||
let f5_2 = (2 * self[5]) as i64;
|
||||
let f7_2 = (2 * self[7]) as i64;
|
||||
let f9_2 = (2 * self[9]) as i64;
|
||||
|
||||
let g0 = _rhs[0] as i64;
|
||||
let g1 = _rhs[1] as i64;
|
||||
let g2 = _rhs[2] as i64;
|
||||
let g3 = _rhs[3] as i64;
|
||||
let g4 = _rhs[4] as i64;
|
||||
let g5 = _rhs[5] as i64;
|
||||
let g6 = _rhs[6] as i64;
|
||||
let g7 = _rhs[7] as i64;
|
||||
let g8 = _rhs[8] as i64;
|
||||
let g9 = _rhs[9] as i64;
|
||||
|
||||
let g1_19 = (19 * _rhs[1]) as i64; /* 1.4*2^29 */
|
||||
let g2_19 = (19 * _rhs[2]) as i64; /* 1.4*2^30; still ok */
|
||||
let g3_19 = (19 * _rhs[3]) as i64;
|
||||
let g4_19 = (19 * _rhs[4]) as i64;
|
||||
let g5_19 = (19 * _rhs[5]) as i64;
|
||||
let g6_19 = (19 * _rhs[6]) as i64;
|
||||
let g7_19 = (19 * _rhs[7]) as i64;
|
||||
let g8_19 = (19 * _rhs[8]) as i64;
|
||||
let g9_19 = (19 * _rhs[9]) as i64;
|
||||
|
||||
let h0 = f0*g0 + f1_2*g9_19 + f2*g8_19 + f3_2*g7_19 + f4*g6_19 + f5_2*g5_19 + f6*g4_19 + f7_2*g3_19 + f8*g2_19 + f9_2*g1_19;
|
||||
let h1 = f0*g1 + f1*g0 + f2*g9_19 + f3*g8_19 + f4*g7_19 + f5*g6_19 + f6*g5_19 + f7*g4_19 + f8*g3_19 + f9*g2_19;
|
||||
let h2 = f0*g2 + f1_2*g1 + f2*g0 + f3_2*g9_19 + f4*g8_19 + f5_2*g7_19 + f6*g6_19 + f7_2*g5_19 + f8*g4_19 + f9_2*g3_19;
|
||||
let h3 = f0*g3 + f1*g2 + f2*g1 + f3*g0 + f4*g9_19 + f5*g8_19 + f6*g7_19 + f7*g6_19 + f8*g5_19 + f9*g4_19;
|
||||
let h4 = f0*g4 + f1_2*g3 + f2*g2 + f3_2*g1 + f4*g0 + f5_2*g9_19 + f6*g8_19 + f7_2*g7_19 + f8*g6_19 + f9_2*g5_19;
|
||||
let h5 = f0*g5 + f1*g4 + f2*g3 + f3*g2 + f4*g1 + f5*g0 + f6*g9_19 + f7*g8_19 + f8*g7_19 + f9*g6_19;
|
||||
let h6 = f0*g6 + f1_2*g5 + f2*g4 + f3_2*g3 + f4*g2 + f5_2*g1 + f6*g0 + f7_2*g9_19 + f8*g8_19 + f9_2*g7_19;
|
||||
let h7 = f0*g7 + f1*g6 + f2*g5 + f3*g4 + f4*g3 + f5*g2 + f6*g1 + f7*g0 + f8*g9_19 + f9*g8_19;
|
||||
let h8 = f0*g8 + f1_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*g9_19;
|
||||
let h9 = f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0;
|
||||
|
||||
FieldElement::combine_coeffs(&[h0, h1, h2, h3, h4, h5, h6, h7, h8, h9])
|
||||
}
|
||||
|
||||
fn square_inner(&self) -> [i64;10] {
|
||||
let f0 = self[0] as i64;
|
||||
let f1 = self[1] as i64;
|
||||
let f2 = self[2] as i64;
|
||||
let f3 = self[3] as i64;
|
||||
let f4 = self[4] as i64;
|
||||
let f5 = self[5] as i64;
|
||||
let f6 = self[6] as i64;
|
||||
let f7 = self[7] as i64;
|
||||
let f8 = self[8] as i64;
|
||||
let f9 = self[9] as i64;
|
||||
let f0_2 = (2 * self[0]) as i64;
|
||||
let f1_2 = (2 * self[1]) as i64;
|
||||
let f2_2 = (2 * self[2]) as i64;
|
||||
let f3_2 = (2 * self[3]) as i64;
|
||||
let f4_2 = (2 * self[4]) as i64;
|
||||
let f5_2 = (2 * self[5]) as i64;
|
||||
let f6_2 = (2 * self[6]) as i64;
|
||||
let f7_2 = (2 * self[7]) as i64;
|
||||
let f5_38 = 38 * f5; // 1.31*2^30
|
||||
let f6_19 = 19 * f6; // 1.31*2^30
|
||||
let f7_38 = 38 * f7; // 1.31*2^30
|
||||
let f8_19 = 19 * f8; // 1.31*2^30
|
||||
let f9_38 = 38 * f9; // 1.31*2^30
|
||||
|
||||
let mut h = [0i64;10];
|
||||
h[0] = f0*f0 + f1_2*f9_38 + f2_2*f8_19 + f3_2*f7_38 + f4_2*f6_19 + f5*f5_38;
|
||||
h[1] = f0_2*f1 + f2*f9_38 + f3_2*f8_19 + f4*f7_38 + f5_2*f6_19;
|
||||
h[2] = f0_2*f2 + f1_2*f1 + f3_2*f9_38 + f4_2*f8_19 + f5_2*f7_38 + f6*f6_19;
|
||||
h[3] = f0_2*f3 + f1_2*f2 + f4*f9_38 + f5_2*f8_19 + f6*f7_38;
|
||||
h[4] = f0_2*f4 + f1_2*f3_2 + f2*f2 + f5_2*f9_38 + f6_2*f8_19 + f7*f7_38;
|
||||
h[5] = f0_2*f5 + f1_2*f4 + f2_2*f3 + f6*f9_38 + f7_2*f8_19;
|
||||
h[6] = f0_2*f6 + f1_2*f5_2 + f2_2*f4 + f3_2*f3 + f7_2*f9_38 + f8*f8_19;
|
||||
h[7] = f0_2*f7 + f1_2*f6 + f2_2*f5 + f3_2*f4 + f8*f9_38;
|
||||
h[8] = f0_2*f8 + f1_2*f7_2 + f2_2*f6 + f3_2*f5_2 + f4*f4 + f9*f9_38;
|
||||
h[9] = f0_2*f9 + f1_2*f8 + f2_2*f7 + f3_2*f6 + f4_2*f5;
|
||||
|
||||
h
|
||||
}
|
||||
|
||||
/// Calculates h = f*f. Can overlap h with f.
|
||||
///
|
||||
/// # Preconditions
|
||||
///
|
||||
/// * |f[i]| bounded by 1.1*2^26, 1.1*2^25, 1.1*2^26, 1.1*2^25, etc.
|
||||
///
|
||||
/// # Postconditions
|
||||
///
|
||||
/// * |h[i]| bounded by 1.1*2^25, 1.1*2^24, 1.1*2^25, 1.1*2^24, etc.
|
||||
pub fn square(&self) -> FieldElement {
|
||||
FieldElement::combine_coeffs(&self.square_inner())
|
||||
}
|
||||
|
||||
/// Square this field element and multiply the result by 2.
|
||||
///
|
||||
/// # Preconditions
|
||||
///
|
||||
/// * |f[i]| bounded by 1.65*2^26, 1.65*2^25, 1.65*2^26, 1.65*2^25, etc.
|
||||
///
|
||||
/// # Postconditions
|
||||
///
|
||||
/// * |h[i]| bounded by 1.01*2^25, 1.01*2^24, 1.01*2^25, 1.01*2^24, etc.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// See fe_mul.c in ref10 implementation for discussion of implementation
|
||||
/// strategy.
|
||||
pub fn square2(&self) -> FieldElement {
|
||||
let mut coeffs = self.square_inner();
|
||||
for i in 0..10 {
|
||||
coeffs[i] += coeffs[i];
|
||||
}
|
||||
FieldElement::combine_coeffs(&coeffs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
/// Requires k > 0; raise self to the 2^(2^k)-th power.
|
||||
fn pow2k(&self, k: u32) -> FieldElement {
|
||||
let mut z = self.square();
|
||||
for _ in 1..k { z = z.square(); }
|
||||
z
|
||||
}
|
||||
|
||||
/// Compute (self^(2^250-1), self^11), used as a helper function
|
||||
/// within invert() and pow22523().
|
||||
///
|
||||
/// XXX This returns an extra intermediate to save computation in
|
||||
/// finding inverses, at the cost of an extra copy when it's not
|
||||
/// used (e.g., when raising to (p-1)/2 or (p-5)/8). Good idea?
|
||||
fn pow22501(&self) -> (FieldElement,FieldElement) {
|
||||
// Instead of managing which temporary variables are used
|
||||
// for what, we define as many as we need and trust the
|
||||
// compiler to reuse stack space as appropriate.
|
||||
//
|
||||
// XXX testing some examples suggests that this does happen,
|
||||
// but it would be good to check asm for this function.
|
||||
//
|
||||
// Each temporary variable t_i is of the form (self)^e_i.
|
||||
// Squaring t_i corresponds to multiplying e_i by 2,
|
||||
// so the pow2k function shifts e_i left by k places.
|
||||
// Multiplying t_i and t_j corresponds to adding e_i + e_j.
|
||||
//
|
||||
// Temporary t_i Nonzero bits of e_i
|
||||
//
|
||||
let t0 = self.square(); // 1 e_0 = 2^1
|
||||
let t1 = t0.square().square(); // 3 e_1 = 2^3
|
||||
let t2 = self * &t1; // 3,0 e_2 = 2^3 + 2^0
|
||||
let t3 = &t0 * &t2; // 3,1,0
|
||||
let t4 = t3.square(); // 4,2,1
|
||||
let t5 = &t2 * &t4; // 4,3,2,1,0
|
||||
let t6 = t5.pow2k(5); // 9,8,7,6,5
|
||||
let t7 = &t6 * &t5; // 9,8,7,6,5,4,3,2,1,0
|
||||
let t8 = t7.pow2k(10); // 19..10
|
||||
let t9 = &t8 * &t7; // 19..0
|
||||
let t10 = t9.pow2k(20); // 39..20
|
||||
let t11 = &t10 * &t9; // 39..0
|
||||
let t12 = t11.pow2k(10); // 49..10
|
||||
let t13 = &t12 * &t7; // 49..0
|
||||
let t14 = t13.pow2k(50); // 99..50
|
||||
let t15 = &t14 * &t13; // 99..0
|
||||
let t16 = t15.pow2k(100); // 199..100
|
||||
let t17 = &t16 * &t15; // 199..0
|
||||
let t18 = t17.pow2k(50); // 249..50
|
||||
let t19 = &t18 * &t13; // 249..0
|
||||
|
||||
(t19, t3)
|
||||
}
|
||||
|
||||
/// Given a nonzero field element, compute its inverse.
|
||||
/// The inverse is computed as self^(p-2), since
|
||||
/// x^(p-2)x = x^(p-1) = 1 (mod p).
|
||||
pub fn invert(&self) -> FieldElement {
|
||||
// The bits of p-2 = 2^255 -19 -2 are 11010111111...11.
|
||||
//
|
||||
// nonzero bits of exponent
|
||||
let (t19, t3) = self.pow22501(); // t19: 249..0 ; t3: 3,1,0
|
||||
let t20 = t19.pow2k(5); // 254..5
|
||||
let t21 = &t20 * &t3; // 254..5,3,1,0
|
||||
|
||||
t21
|
||||
}
|
||||
|
||||
/// Raise this field element to the power (p-5)/8 = 2^252 -3.
|
||||
/// Used in decoding.
|
||||
pub fn pow_p58(&self) -> FieldElement {
|
||||
// The bits of (p-5)/8 are 101111.....11.
|
||||
//
|
||||
// nonzero bits of exponent
|
||||
let (t19, _) = self.pow22501(); // 249..0
|
||||
let t20 = t19.pow2k(2); // 251..2
|
||||
let t21 = self * &t20; // 251..2,0
|
||||
|
||||
t21
|
||||
}
|
||||
|
||||
/// chi calculates `self^((p-1)/2)`.
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// * If this element is a non-zero square, returns `1`.
|
||||
/// * If it is zero, returns `0`.
|
||||
/// * If it is non-square, returns `-1`.
|
||||
pub fn chi(&self) -> FieldElement { // extra25519.chi
|
||||
// The bits of (p-1)/2 = 2^254 -10 are 0110111111...11.
|
||||
//
|
||||
// nonzero bits of exponent
|
||||
let (t19, _) = self.pow22501(); // 249..0
|
||||
let t20 = t19.pow2k(4); // 253..4
|
||||
let t21 = self.square(); // 1
|
||||
let t22 = t21.square(); // 2
|
||||
let t23 = &t22 * &t21; // 2,1
|
||||
let t24 = &t20 * &t23; // 253..4,2,1
|
||||
|
||||
t24
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use field::*;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_fieldelement_a_mul_a(b: &mut Bencher) {
|
||||
let a = FieldElement::from_bytes(&A_BYTES);
|
||||
b.iter(|| &a*&a);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fieldelement_a_sq(b: &mut Bencher) {
|
||||
let a = FieldElement::from_bytes(&A_BYTES);
|
||||
b.iter(|| a.square());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_fieldelement_a_inv(b: &mut Bencher) {
|
||||
let a = FieldElement::from_bytes(&A_BYTES);
|
||||
b.iter(|| a.invert());
|
||||
}
|
||||
|
||||
/// Random element a of GF(2^255-19), from Sage
|
||||
/// a = 1070314506888354081329385823235218444233221\
|
||||
/// 2228051251926706380353716438957572
|
||||
static A_BYTES: [u8;32] =
|
||||
[ 0x04, 0xfe, 0xdf, 0x98, 0xa7, 0xfa, 0x0a, 0x68,
|
||||
0x84, 0x92, 0xbd, 0x59, 0x08, 0x07, 0xa7, 0x03,
|
||||
0x9e, 0xd1, 0xf6, 0xf2, 0xe1, 0xd9, 0xe2, 0xa4,
|
||||
0xa4, 0x51, 0x47, 0x36, 0xf3, 0xc3, 0xa9, 0x17];
|
||||
|
||||
/// Byte representation of a**2
|
||||
static ASQ_BYTES: [u8;32] =
|
||||
[ 0x75, 0x97, 0x24, 0x9e, 0xe6, 0x06, 0xfe, 0xab,
|
||||
0x24, 0x04, 0x56, 0x68, 0x07, 0x91, 0x2d, 0x5d,
|
||||
0x0b, 0x0f, 0x3f, 0x1c, 0xb2, 0x6e, 0xf2, 0xe2,
|
||||
0x63, 0x9c, 0x12, 0xba, 0x73, 0x0b, 0xe3, 0x62];
|
||||
|
||||
/// Byte representation of 1/a
|
||||
static AINV_BYTES: [u8;32] =
|
||||
[0x96, 0x1b, 0xcd, 0x8d, 0x4d, 0x5e, 0xa2, 0x3a,
|
||||
0xe9, 0x36, 0x37, 0x93, 0xdb, 0x7b, 0x4d, 0x70,
|
||||
0xb8, 0x0d, 0xc0, 0x55, 0xd0, 0x4c, 0x1d, 0x7b,
|
||||
0x90, 0x71, 0xd8, 0xe9, 0xb6, 0x18, 0xe6, 0x30];
|
||||
|
||||
/// Byte representation of a^((p-5)/8)
|
||||
static AP58_BYTES: [u8;32] =
|
||||
[0x6a, 0x4f, 0x24, 0x89, 0x1f, 0x57, 0x60, 0x36,
|
||||
0xd0, 0xbe, 0x12, 0x3c, 0x8f, 0xf5, 0xb1, 0x59,
|
||||
0xe0, 0xf0, 0xb8, 0x1b, 0x20, 0xd2, 0xb5, 0x1f,
|
||||
0x15, 0x21, 0xf9, 0xe3, 0xe1, 0x61, 0x21, 0x55];
|
||||
|
||||
#[test]
|
||||
fn test_fieldelement_a_mul_a() {
|
||||
let a = FieldElement::from_bytes(&A_BYTES);
|
||||
let asq = FieldElement::from_bytes(&ASQ_BYTES);
|
||||
assert_eq!(asq, &a*&a);
|
||||
assert_eq!(asq, a.square());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fieldelement_a_square2() {
|
||||
let a = FieldElement::from_bytes(&A_BYTES);
|
||||
let asq = FieldElement::from_bytes(&ASQ_BYTES);
|
||||
assert_eq!(a.square2(), &asq+&asq);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fieldelement_a_inv() {
|
||||
let a = FieldElement::from_bytes(&A_BYTES);
|
||||
let ainv = FieldElement::from_bytes(&AINV_BYTES);
|
||||
assert_eq!(ainv, a.invert());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fieldelement_a_p58() {
|
||||
let a = FieldElement::from_bytes(&A_BYTES);
|
||||
let ap58 = FieldElement::from_bytes(&AP58_BYTES);
|
||||
assert_eq!(ap58, a.pow_p58());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fieldelement_a_chi() {
|
||||
let a = FieldElement::from_bytes(&A_BYTES);
|
||||
// a is square
|
||||
assert_eq!(a.chi(), FieldElement::one());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fieldelement_eq() {
|
||||
let a = FieldElement::from_bytes(&A_BYTES);
|
||||
let ainv = FieldElement::from_bytes(&AINV_BYTES);
|
||||
assert!(a == a);
|
||||
assert!(a != ainv);
|
||||
}
|
||||
|
||||
/// Notice that the last element has the high bit set, which
|
||||
/// should be ignored
|
||||
static B_BYTES: [u8;32] =
|
||||
[113, 191, 169, 143, 91, 234, 121, 15, 241, 131, 217, 36, 230, 101, 92, 234, 8, 208, 170, 251, 97, 127, 70, 210, 58, 23, 166, 87, 240, 169, 184, 178];
|
||||
|
||||
static B_LIMBS: FieldElement = FieldElement(
|
||||
[-5652623, 8034020, 8266223, -13556020, -5672552, -5582839, -12603138, 15161929, -16418207, 13296296]);
|
||||
|
||||
#[test]
|
||||
fn test_fieldelement_frombytes_highbit_is_ignored() {
|
||||
let mut cleared_bytes = B_BYTES.clone();
|
||||
cleared_bytes[31] &= 127u8;
|
||||
let orig_elt = FieldElement::from_bytes(&B_BYTES);
|
||||
let cleared_elt = FieldElement::from_bytes(&cleared_bytes);
|
||||
for i in 0..10 {
|
||||
assert!(orig_elt[i] == cleared_elt[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fieldelement_to_bytes() {
|
||||
let test_elt = FieldElement::from_bytes(&B_BYTES);
|
||||
for i in 0..10 {
|
||||
assert!(test_elt[i] == B_LIMBS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fieldelement_from_bytes() {
|
||||
let test_bytes = B_LIMBS.to_bytes();
|
||||
for i in 0..31 {
|
||||
assert!(test_bytes[i] == B_BYTES[i]);
|
||||
}
|
||||
// high bit is set to zero in to_bytes
|
||||
assert!(test_bytes[31] == (B_BYTES[31] & 127u8));
|
||||
}
|
||||
}
|
||||
1481
src/lib.rs
Normal file
1481
src/lib.rs
Normal file
File diff suppressed because it is too large
Load diff
527
src/scalar.rs
Normal file
527
src/scalar.rs
Normal file
|
|
@ -0,0 +1,527 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// To the extent possible under law, the authors have waived all
|
||||
// copyright and related or neighboring rights to curve25519-dalek,
|
||||
// using the Creative Commons "CC0" public domain dedication. See
|
||||
// <http://creativecommons.org/publicdomain/zero/.0/> for full
|
||||
// details.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! Arithmetic for scalar multiplication.
|
||||
//!
|
||||
//! The Ed25519 basepoint P has prime order
|
||||
//!
|
||||
//! l = 2^252 + 27742317777372353535851937790883648493.
|
||||
//!
|
||||
//! Thus a multiple `aP` of the basepoint (with a ∈ ℤ) depends only
|
||||
//! on the value of `a (mod l)`, or equivalently, the image of `a` in
|
||||
//! the quotient ℤ/lℤ.
|
||||
//!
|
||||
//! The `Scalar` struct represents an element in ℤ/lℤ.
|
||||
//!
|
||||
//! Arithmetic operations on `Scalar`s are done using 12 21-bit limbs.
|
||||
//! However, in contrast to `FieldElement`s, `Scalar`s are stored in
|
||||
//! memory as bytes, allowing easy access to the bits of the `Scalar`.
|
||||
|
||||
use std::clone::Clone;
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
use field::{load3, load4};
|
||||
|
||||
/// The `Scalar` struct represents an element in ℤ/lℤ, where
|
||||
///
|
||||
/// l = 2^252 + 27742317777372353535851937790883648493
|
||||
///
|
||||
/// is the order of the basepoint.
|
||||
#[derive(Copy)]
|
||||
pub struct Scalar(pub [u8; 32]);
|
||||
|
||||
impl Clone for Scalar {
|
||||
fn clone(&self) -> Scalar { *self }
|
||||
}
|
||||
|
||||
impl Index<usize> for Scalar {
|
||||
type Output = u8;
|
||||
|
||||
fn index<'a>(&'a self, _index: usize) -> &'a u8 {
|
||||
let ret: &'a u8 = &(self.0[_index]);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for Scalar {
|
||||
fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut u8 {
|
||||
let ret: &'a mut u8 = &mut(self.0[_index]);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl Scalar {
|
||||
/// Construct the additive identity
|
||||
pub fn zero() -> Self {
|
||||
Scalar([0u8; 32])
|
||||
}
|
||||
|
||||
/// Construct the multiplicative identity
|
||||
pub fn one() -> Self {
|
||||
Scalar([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ])
|
||||
}
|
||||
|
||||
/// Compute a width-5 "Non-Adjacent Form" of this scalar.
|
||||
///
|
||||
/// A width-`w` NAF of a positive integer `k` is an expression
|
||||
/// `k = sum(k[i]*2^i for i in range(l))`, where each nonzero
|
||||
/// coefficient `k[i]` is odd and bounded by `|k[i]| < 2^(w-1)`,
|
||||
/// `k[l-1]` is nonzero, and at most one of any `w` consecutive
|
||||
/// coefficients is nonzero. (Hankerson, Menezes, Vanstone; def 3.32).
|
||||
///
|
||||
/// Intuitively, this is like a binary expansion, except that we
|
||||
/// allow some coefficients to grow up to `2^(w-1)` so that the
|
||||
/// nonzero coefficients are as sparse as possible.
|
||||
pub fn non_adjacent_form(&self) -> [i8;256] {
|
||||
// Step 1: write out bits of the scalar
|
||||
let mut naf = [0i8; 256];
|
||||
for i in 0..256 {
|
||||
// As i runs from 0..256, the bottom 3 bits index the bit,
|
||||
// while the upper bits index the byte.
|
||||
naf[i] = ((self.0[i>>3] >> (i&7)) & 1u8) as i8;
|
||||
}
|
||||
|
||||
// Step 2: zero coefficients by carrying them upwards or downwards
|
||||
'bits: for i in 0..256 {
|
||||
if naf[i] == 0 { continue 'bits; }
|
||||
'window: for b in 1..6 {
|
||||
if i+b >= 256 { break 'window; }
|
||||
if naf[i+b] == 0 { continue 'window; }
|
||||
let potential_carry = naf[i+b] << b;
|
||||
if naf[i+b] + potential_carry <= 15 {
|
||||
// Eliminate naf[i+b] by carrying its value onto naf[i]
|
||||
naf[i] += potential_carry;
|
||||
naf[i+b] = 0;
|
||||
} else if naf[i+b] - potential_carry >= -15 {
|
||||
// Eliminate naf[i+b] by carrying its value upwards.
|
||||
naf[i] -= potential_carry; // Subtract 2^(i+b)
|
||||
'carry: for k in i+b..256 {
|
||||
if naf[k] != 0 {
|
||||
// Since naf[k] = 0 or 1 for k > i, naf[k] == 1.
|
||||
naf[k] = 0; // Subtract 2^k
|
||||
} else {
|
||||
// By now we have subtracted 2^k =
|
||||
// 2^(i+b) + 2^(i+b) + 2^(i+b+1) + ... + 2^(k-1).
|
||||
naf[k] = 1; // Add back 2^k.
|
||||
break 'carry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
naf
|
||||
}
|
||||
|
||||
/// Create a scalar by packing 12 21-bit limbs into bytes.
|
||||
fn pack_limbs(limbs: &[i64;12]) -> Scalar {
|
||||
let mut s = Scalar::zero();
|
||||
s[0] = (limbs[ 0] >> 0) as u8;
|
||||
s[1] = (limbs[ 0] >> 8) as u8;
|
||||
s[2] = ((limbs[ 0] >> 16) | (limbs[ 1] << 5)) as u8;
|
||||
s[3] = (limbs[ 1] >> 3) as u8;
|
||||
s[4] = (limbs[ 1] >> 11) as u8;
|
||||
s[5] = ((limbs[ 1] >> 19) | (limbs[ 2] << 2)) as u8;
|
||||
s[6] = (limbs[ 2] >> 6) as u8;
|
||||
s[7] = ((limbs[ 2] >> 14) | (limbs[ 3] << 7)) as u8;
|
||||
s[8] = (limbs[ 3] >> 1) as u8;
|
||||
s[9] = (limbs[ 3] >> 9) as u8;
|
||||
s[10] = ((limbs[ 3] >> 17) | (limbs[ 4] << 4)) as u8;
|
||||
s[11] = (limbs[ 4] >> 4) as u8;
|
||||
s[12] = (limbs[ 4] >> 12) as u8;
|
||||
s[13] = ((limbs[ 4] >> 20) | (limbs[ 5] << 1)) as u8;
|
||||
s[14] = (limbs[ 5] >> 7) as u8;
|
||||
s[15] = ((limbs[ 5] >> 15) | (limbs[ 6] << 6)) as u8;
|
||||
s[16] = (limbs[ 6] >> 2) as u8;
|
||||
s[17] = (limbs[ 6] >> 10) as u8;
|
||||
s[18] = ((limbs[ 6] >> 18) | (limbs[ 7] << 3)) as u8;
|
||||
s[19] = (limbs[ 7] >> 5) as u8;
|
||||
s[20] = (limbs[ 7] >> 13) as u8;
|
||||
s[21] = (limbs[ 8] >> 0) as u8;
|
||||
s[22] = (limbs[ 8] >> 8) as u8;
|
||||
s[23] = ((limbs[ 8] >> 16) | (limbs[ 9] << 5)) as u8;
|
||||
s[24] = (limbs[ 9] >> 3) as u8;
|
||||
s[25] = (limbs[ 9] >> 11) as u8;
|
||||
s[26] = ((limbs[ 9] >> 19) | (limbs[10] << 2)) as u8;
|
||||
s[27] = (limbs[10] >> 6) as u8;
|
||||
s[28] = ((limbs[10] >> 14) | (limbs[11] << 7)) as u8;
|
||||
s[29] = (limbs[11] >> 1) as u8;
|
||||
s[30] = (limbs[11] >> 9) as u8;
|
||||
s[31] = (limbs[11] >> 17) as u8;
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
// Unpack a scalar into 12 21-bit limbs.
|
||||
fn unpack_limbs(&self) -> [i64;12] {
|
||||
let mask_21bits: i64 = (1 << 21) -1;
|
||||
let mut a = [0i64;12];
|
||||
a[ 0] = mask_21bits & load3(&self.0[ 0..]) ;
|
||||
a[ 1] = mask_21bits & (load4(&self.0[ 2..]) >> 5);
|
||||
a[ 2] = mask_21bits & (load3(&self.0[ 5..]) >> 2);
|
||||
a[ 3] = mask_21bits & (load4(&self.0[ 7..]) >> 7);
|
||||
a[ 4] = mask_21bits & (load4(&self.0[10..]) >> 4);
|
||||
a[ 5] = mask_21bits & (load3(&self.0[13..]) >> 1);
|
||||
a[ 6] = mask_21bits & (load4(&self.0[15..]) >> 6);
|
||||
a[ 7] = mask_21bits & (load3(&self.0[18..]) >> 3);
|
||||
a[ 8] = mask_21bits & load3(&self.0[21..]) ;
|
||||
a[ 9] = mask_21bits & (load4(&self.0[23..]) >> 5);
|
||||
a[10] = mask_21bits & (load3(&self.0[26..]) >> 2);
|
||||
a[11] = load4(&self.0[28..]) >> 7 ;
|
||||
|
||||
a
|
||||
}
|
||||
|
||||
/// Write this scalar in radix 16, with coefficients in `[-8,8)`,
|
||||
/// i.e., compute `a_i` such that
|
||||
///
|
||||
/// a = a_0 + a_1*16^1 + ... + a_63*16^63,
|
||||
///
|
||||
/// with `-8 ≤ a_i < 8` for `0 ≤ i < 63` and `-8 ≤ a_63 ≤ 8`.
|
||||
///
|
||||
/// Precondition: self[31] <= 127. This is the case whenever
|
||||
/// `self` is reduced.
|
||||
pub fn to_radix_16(&self) -> [i8;64] {
|
||||
debug_assert!(self[31] <= 127);
|
||||
let mut output = [0i8; 64];
|
||||
|
||||
// Step 1: change radix.
|
||||
// Convert from radix 256 (bytes) to radix 16 (nibbles)
|
||||
#[inline(always)]
|
||||
fn bot_half(x: u8) -> u8 { (x >> 0) & 15 }
|
||||
#[inline(always)]
|
||||
fn top_half(x: u8) -> u8 { (x >> 4) & 15 }
|
||||
|
||||
for i in 0..32 {
|
||||
output[2*i ] = bot_half(self[i]) as i8;
|
||||
output[2*i+1] = top_half(self[i]) as i8;
|
||||
}
|
||||
// Precondition note: since self[31] <= 127, output[63] <= 7
|
||||
|
||||
// Step 2: recenter coefficients from [0,16) to [-8,8)
|
||||
for i in 0..63 {
|
||||
let carry = (output[i] + 8) >> 4;
|
||||
output[i ] -= carry << 4;
|
||||
output[i+1] += carry;
|
||||
}
|
||||
// Precondition note: output[63] is not recentered. It
|
||||
// increases by carry <= 1. Thus output[63] <= 8.
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
/// Reduce limbs in-place. Reduction is mod
|
||||
///
|
||||
/// l = 2^252 + 27742317777372353535851937790883648493,
|
||||
///
|
||||
/// so
|
||||
///
|
||||
/// 2^252 = -27742317777372353535851937790883648493 (mod l).
|
||||
///
|
||||
/// We can write the right-hand side in 21-bit limbs as
|
||||
///
|
||||
/// rhs = 666643 * 2^0
|
||||
/// + 470296 * 2^21
|
||||
/// + 654183 * 2^42
|
||||
/// - 997805 * 2^63
|
||||
/// + 136657 * 2^84
|
||||
/// - 683901 * 2^105
|
||||
///
|
||||
/// The (12+k)-th limb of `limbs` is the coefficient of
|
||||
///
|
||||
/// 2^(252 + 21*k)
|
||||
///
|
||||
/// since 12*21 = 252. By the above, we have that
|
||||
///
|
||||
/// c * 2^(252 + 21*k) = c * 666643 * 2^(21*k)
|
||||
/// + c * 470296 * 2^(42*k) + ...
|
||||
///
|
||||
/// so we can eliminate it by adding those values to the lower
|
||||
/// limbs. Reduction mod l amounts to eliminating all of the
|
||||
/// high limbs while carrying as appropriate to prevent
|
||||
/// overflows in the lower limbs.
|
||||
fn reduce_limbs(mut limbs: &mut [i64;24]) {
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
fn do_reduction(limbs: &mut [i64;24], i:usize) {
|
||||
limbs[i - 12] += limbs[i] * 666643;
|
||||
limbs[i - 11] += limbs[i] * 470296;
|
||||
limbs[i - 10] += limbs[i] * 654183;
|
||||
limbs[i - 9] -= limbs[i] * 997805;
|
||||
limbs[i - 8] += limbs[i] * 136657;
|
||||
limbs[i - 7] -= limbs[i] * 683901;
|
||||
limbs[i] = 0;
|
||||
}
|
||||
/// Carry excess from the `i`-th limb into the `(i+1)`-th limb.
|
||||
/// Postcondition: `0 <= limbs[i] < 2^21`.
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
fn do_carry_uncentered(limbs: &mut [i64; 24], i: usize) {
|
||||
let carry: i64 = limbs[i] >> 21;
|
||||
limbs[i+1] += carry;
|
||||
limbs[i ] -= carry << 21;
|
||||
}
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
/// Carry excess from the `i`-th limb into the `(i+1)`-th limb.
|
||||
/// Postcondition: `-2^20 <= limbs[i] < 2^20`.
|
||||
fn do_carry_centered(limbs: &mut [i64;24], i:usize) {
|
||||
let carry: i64 = (limbs[i] + (1<<20)) >> 21;
|
||||
limbs[i+1] += carry;
|
||||
limbs[i ] -= carry << 21;
|
||||
}
|
||||
|
||||
for i in 0..23 {
|
||||
do_carry_centered(&mut limbs, i);
|
||||
}
|
||||
for i in (0..23).filter(|x| x % 2 == 1) {
|
||||
do_carry_centered(&mut limbs, i);
|
||||
}
|
||||
|
||||
do_reduction(&mut limbs, 23);
|
||||
do_reduction(&mut limbs, 22);
|
||||
do_reduction(&mut limbs, 21);
|
||||
do_reduction(&mut limbs, 20);
|
||||
do_reduction(&mut limbs, 19);
|
||||
do_reduction(&mut limbs, 18);
|
||||
|
||||
for i in (6..18).filter(|x| x % 2 == 0) {
|
||||
do_carry_centered(&mut limbs, i);
|
||||
}
|
||||
for i in (6..16).filter(|x| x % 2 == 1) {
|
||||
do_carry_centered(&mut limbs, i);
|
||||
}
|
||||
|
||||
do_reduction(&mut limbs, 17);
|
||||
do_reduction(&mut limbs, 16);
|
||||
do_reduction(&mut limbs, 15);
|
||||
do_reduction(&mut limbs, 14);
|
||||
do_reduction(&mut limbs, 13);
|
||||
do_reduction(&mut limbs, 12);
|
||||
|
||||
for i in (0..12).filter(|x| x % 2 == 0) {
|
||||
do_carry_centered(&mut limbs, i);
|
||||
}
|
||||
for i in (0..12).filter(|x| x % 2 == 1) {
|
||||
do_carry_centered(&mut limbs, i);
|
||||
}
|
||||
|
||||
do_reduction(&mut limbs, 12);
|
||||
|
||||
for i in 0..12 {
|
||||
do_carry_uncentered(&mut limbs, i);
|
||||
}
|
||||
|
||||
do_reduction(&mut limbs, 12);
|
||||
|
||||
for i in 0..11 {
|
||||
do_carry_uncentered(&mut limbs, i);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute `ab+c (mod l)`.
|
||||
pub fn multiply_add(a: &Scalar, b: &Scalar, c: &Scalar) -> Scalar {
|
||||
// Unpack scalars into limbs
|
||||
let al = a.unpack_limbs();
|
||||
let bl = b.unpack_limbs();
|
||||
let cl = c.unpack_limbs();
|
||||
|
||||
let mut result = [0i64;24];
|
||||
|
||||
// Multiply a and b, and add c
|
||||
result[0] = cl[0] + al[0]*bl[0];
|
||||
result[1] = cl[1] + al[0]*bl[1] + al[1]*bl[0];
|
||||
result[2] = cl[2] + al[0]*bl[2] + al[1]*bl[1] + al[2]*bl[0];
|
||||
result[3] = cl[3] + al[0]*bl[3] + al[1]*bl[2] + al[2]*bl[1] + al[3]*bl[0];
|
||||
result[4] = cl[4] + al[0]*bl[4] + al[1]*bl[3] + al[2]*bl[2] + al[3]*bl[1] + al[4]*bl[0];
|
||||
result[5] = cl[5] + al[0]*bl[5] + al[1]*bl[4] + al[2]*bl[3] + al[3]*bl[2] + al[4]*bl[1] + al[5]*bl[0];
|
||||
result[6] = cl[6] + al[0]*bl[6] + al[1]*bl[5] + al[2]*bl[4] + al[3]*bl[3] + al[4]*bl[2] + al[5]*bl[1] + al[6]*bl[0];
|
||||
result[7] = cl[7] + al[0]*bl[7] + al[1]*bl[6] + al[2]*bl[5] + al[3]*bl[4] + al[4]*bl[3] + al[5]*bl[2] + al[6]*bl[1] + al[7]*bl[0];
|
||||
result[8] = cl[8] + al[0]*bl[8] + al[1]*bl[7] + al[2]*bl[6] + al[3]*bl[5] + al[4]*bl[4] + al[5]*bl[3] + al[6]*bl[2] + al[7]*bl[1] + al[8]*bl[0];
|
||||
result[9] = cl[9] + al[0]*bl[9] + al[1]*bl[8] + al[2]*bl[7] + al[3]*bl[6] + al[4]*bl[5] + al[5]*bl[4] + al[6]*bl[3] + al[7]*bl[2] + al[8]*bl[1] + al[9]*bl[0];
|
||||
result[10] = cl[10] + al[0]*bl[10] + al[1]*bl[9] + al[2]*bl[8] + al[3]*bl[7] + al[4]*bl[6] + al[5]*bl[5] + al[6]*bl[4] + al[7]*bl[3] + al[8]*bl[2] + al[9]*bl[1] + al[10]*bl[0];
|
||||
result[11] = cl[11] + al[0]*bl[11] + al[1]*bl[10] + al[2]*bl[9] + al[3]*bl[8] + al[4]*bl[7] + al[5]*bl[6] + al[6]*bl[5] + al[7]*bl[4] + al[8]*bl[3] + al[9]*bl[2] + al[10]*bl[1] + al[11]*bl[0];
|
||||
result[12] = al[1]*bl[11] + al[2]*bl[10] + al[3]*bl[9] + al[4]*bl[8] + al[5]*bl[7] + al[6]*bl[6] + al[7]*bl[5] + al[8]*bl[4] + al[9]*bl[3] + al[10]*bl[2] + al[11]*bl[1];
|
||||
result[13] = al[2]*bl[11] + al[3]*bl[10] + al[4]*bl[9] + al[5]*bl[8] + al[6]*bl[7] + al[7]*bl[6] + al[8]*bl[5] + al[9]*bl[4] + al[10]*bl[3] + al[11]*bl[2];
|
||||
result[14] = al[3]*bl[11] + al[4]*bl[10] + al[5]*bl[9] + al[6]*bl[8] + al[7]*bl[7] + al[8]*bl[6] + al[9]*bl[5] + al[10]*bl[4] + al[11]*bl[3];
|
||||
result[15] = al[4]*bl[11] + al[5]*bl[10] + al[6]*bl[9] + al[7]*bl[8] + al[8]*bl[7] + al[9]*bl[6] + al[10]*bl[5] + al[11]*bl[4];
|
||||
result[16] = al[5]*bl[11] + al[6]*bl[10] + al[7]*bl[9] + al[8]*bl[8] + al[9]*bl[7] + al[10]*bl[6] + al[11]*bl[5];
|
||||
result[17] = al[6]*bl[11] + al[7]*bl[10] + al[8]*bl[9] + al[9]*bl[8] + al[10]*bl[7] + al[11]*bl[6];
|
||||
result[18] = al[7]*bl[11] + al[8]*bl[10] + al[9]*bl[9] + al[10]*bl[8] + al[11]*bl[7];
|
||||
result[19] = al[8]*bl[11] + al[9]*bl[10] + al[10]*bl[9] + al[11]*bl[8];
|
||||
result[20] = al[9]*bl[11] + al[10]*bl[10] + al[11]*bl[9];
|
||||
result[21] = al[10]*bl[11] + al[11]*bl[10];
|
||||
result[22] = al[11]*bl[11];
|
||||
result[23] = 0i64;
|
||||
|
||||
// reduce limbs and pack into output
|
||||
Scalar::reduce_limbs(&mut result);
|
||||
Scalar::pack_limbs(array_ref!(result, 0, 12))
|
||||
}
|
||||
|
||||
/// Reduce a 512-bit little endian number mod l
|
||||
pub fn reduce(input: &[u8;64]) -> Scalar {
|
||||
let mut s = [0i64;24];
|
||||
|
||||
// XXX express this as two unpack_limbs
|
||||
// some issues re: masking with the top byte of the 32byte input
|
||||
let mask_21bits: i64 = (1 << 21) -1;
|
||||
s[0] = mask_21bits & load3(&input[ 0..]) ;
|
||||
s[1] = mask_21bits & (load4(&input[ 2..]) >> 5);
|
||||
s[2] = mask_21bits & (load3(&input[ 5..]) >> 2);
|
||||
s[3] = mask_21bits & (load4(&input[ 7..]) >> 7);
|
||||
s[4] = mask_21bits & (load4(&input[10..]) >> 4);
|
||||
s[5] = mask_21bits & (load3(&input[13..]) >> 1);
|
||||
s[6] = mask_21bits & (load4(&input[15..]) >> 6);
|
||||
s[7] = mask_21bits & (load3(&input[18..]) >> 3);
|
||||
s[8] = mask_21bits & load3(&input[21..]) ;
|
||||
s[9] = mask_21bits & (load4(&input[23..]) >> 5);
|
||||
s[10] = mask_21bits & (load3(&input[26..]) >> 2);
|
||||
s[11] = mask_21bits & (load4(&input[28..]) >> 7);
|
||||
s[12] = mask_21bits & (load4(&input[31..]) >> 4);
|
||||
s[13] = mask_21bits & (load3(&input[34..]) >> 1);
|
||||
s[14] = mask_21bits & (load4(&input[36..]) >> 6);
|
||||
s[15] = mask_21bits & (load3(&input[39..]) >> 3);
|
||||
s[16] = mask_21bits & load3(&input[42..]) ;
|
||||
s[17] = mask_21bits & (load4(&input[44..]) >> 5);
|
||||
s[18] = mask_21bits & (load3(&input[47..]) >> 2);
|
||||
s[19] = mask_21bits & (load4(&input[49..]) >> 7);
|
||||
s[20] = mask_21bits & (load4(&input[52..]) >> 4);
|
||||
s[21] = mask_21bits & (load3(&input[55..]) >> 1);
|
||||
s[22] = mask_21bits & (load4(&input[57..]) >> 6);
|
||||
s[23] = load4(&input[60..]) >> 3 ;
|
||||
|
||||
// XXX replacing the previous code in this function with the
|
||||
// call to reduce_limbs adds two extra carry passes (the ones
|
||||
// at the top of the reduce_limbs function). Otherwise they
|
||||
// are identical. The test seems to work OK but it would be
|
||||
// good to check that this really is OK to add.
|
||||
Scalar::reduce_limbs(&mut s);
|
||||
|
||||
Scalar::pack_limbs(array_ref!(s,0,12))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn bench_scalar_multiply_add(b: &mut Bencher) {
|
||||
b.iter(|| Scalar::multiply_add(&X, &Y, &Z) );
|
||||
}
|
||||
|
||||
/// x = 2238329342913194256032495932344128051776374960164957527413114840482143558222
|
||||
static X: Scalar = Scalar(
|
||||
[0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84,
|
||||
0x59, 0x13, 0xb4, 0x64, 0x1b, 0xc2, 0x7d, 0x52,
|
||||
0x52, 0xa5, 0x85, 0x10, 0x1b, 0xcc, 0x42, 0x44,
|
||||
0xd4, 0x49, 0xf4, 0xa8, 0x79, 0xd9, 0xf2, 0x04]);
|
||||
/// y = 2592331292931086675770238855846338635550719849568364935475441891787804997264
|
||||
static Y: Scalar = Scalar(
|
||||
[0x90, 0x76, 0x33, 0xfe, 0x1c, 0x4b, 0x66, 0xa4,
|
||||
0xa2, 0x8d, 0x2d, 0xd7, 0x67, 0x83, 0x86, 0xc3,
|
||||
0x53, 0xd0, 0xde, 0x54, 0x55, 0xd4, 0xfc, 0x9d,
|
||||
0xe8, 0xef, 0x7a, 0xc3, 0x1f, 0x35, 0xbb, 0x05]);
|
||||
/// z = 5033871415930814945849241457262266927579821285980625165479289807629491019013
|
||||
static Z: Scalar = Scalar(
|
||||
[0x05, 0x9d, 0x3e, 0x0b, 0x09, 0x26, 0x50, 0x3d,
|
||||
0xa3, 0x84, 0xa1, 0x3c, 0x92, 0x7a, 0xc2, 0x06,
|
||||
0x41, 0x98, 0xcf, 0x34, 0x3a, 0x24, 0xd5, 0xb7,
|
||||
0xeb, 0x33, 0x6a, 0x2d, 0xfc, 0x11, 0x21, 0x0b]);
|
||||
/// w = 3486911242272497535104403593250518247409663771668155364040899665266216860804
|
||||
static W: Scalar = Scalar(
|
||||
[0x84, 0xfc, 0xbc, 0x4f, 0x78, 0x12, 0xa0, 0x06,
|
||||
0xd7, 0x91, 0xd9, 0x7a, 0x3a, 0x27, 0xdd, 0x1e,
|
||||
0x21, 0x43, 0x45, 0xf7, 0xb1, 0xb9, 0x56, 0x7a,
|
||||
0x81, 0x30, 0x73, 0x44, 0x96, 0x85, 0xb5, 0x07]);
|
||||
|
||||
/// x*y = 5690045403673944803228348699031245560686958845067437804563560795922180092780
|
||||
static X_TIMES_Y: Scalar = Scalar(
|
||||
[0x6c, 0x33, 0x74, 0xa1, 0x89, 0x4f, 0x62, 0x21,
|
||||
0x0a, 0xaa, 0x2f, 0xe1, 0x86, 0xa6, 0xf9, 0x2c,
|
||||
0xe0, 0xaa, 0x75, 0xc2, 0x77, 0x95, 0x81, 0xc2,
|
||||
0x95, 0xfc, 0x08, 0x17, 0x9a, 0x73, 0x94, 0x0c]);
|
||||
|
||||
static A_SCALAR: Scalar = Scalar([
|
||||
0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d,
|
||||
0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d,
|
||||
0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1,
|
||||
0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09]);
|
||||
|
||||
static A_NAF: [i8;256] =
|
||||
[0,13,0,0,0,0,0,0,0,7,0,0,0,0,0,0,-9,0,0,0,0,-11,0,0,0,0,3,0,0,0,0,1,
|
||||
0,0,0,0,9,0,0,0,0,-5,0,0,0,0,0,0,3,0,0,0,0,11,0,0,0,0,11,0,0,0,0,0,
|
||||
-9,0,0,0,0,0,-3,0,0,0,0,9,0,0,0,0,0,1,0,0,0,0,0,0,-1,0,0,0,0,0,9,0,
|
||||
0,0,0,-15,0,0,0,0,-7,0,0,0,0,-9,0,0,0,0,0,5,0,0,0,0,13,0,0,0,0,0,-3,0,
|
||||
0,0,0,-11,0,0,0,0,-7,0,0,0,0,-13,0,0,0,0,11,0,0,0,0,-9,0,0,0,0,0,1,0,0,
|
||||
0,0,0,-15,0,0,0,0,1,0,0,0,0,7,0,0,0,0,0,0,0,0,5,0,0,0,0,0,13,0,0,0,
|
||||
0,0,0,11,0,0,0,0,0,15,0,0,0,0,0,-9,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,7,
|
||||
0,0,0,0,0,-15,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,15,0,0,0,0,0,1,0,0,0,0];
|
||||
|
||||
#[test]
|
||||
fn test_non_adjacent_form() {
|
||||
let naf = A_SCALAR.non_adjacent_form();
|
||||
for i in 0..256 {
|
||||
assert_eq!(naf[i], A_NAF[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scalar_multiply_by_one() {
|
||||
let one = Scalar::one();
|
||||
let zero = Scalar::zero();
|
||||
let test_scalar = Scalar::multiply_add(&X, &one, &zero);
|
||||
for i in 0..32 {
|
||||
assert!(test_scalar[i] == X[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scalar_multiply_only() {
|
||||
let zero = Scalar::zero();
|
||||
let test_scalar = Scalar::multiply_add(&X, &Y, &zero);
|
||||
for i in 0..32 {
|
||||
assert!(test_scalar[i] == X_TIMES_Y[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scalar_multiply_add() {
|
||||
let test_scalar = Scalar::multiply_add(&X, &Y, &Z);
|
||||
for i in 0..32 {
|
||||
assert!(test_scalar[i] == W[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scalar_reduce() {
|
||||
let mut bignum = [0u8;64];
|
||||
// set bignum = x + 2^256x
|
||||
for i in 0..32 {
|
||||
bignum[ i] = X[i];
|
||||
bignum[32+i] = X[i];
|
||||
}
|
||||
// 3958878930004874126169954872055634648693766179881526445624823978500314864344
|
||||
// = x + 2^256x (mod l)
|
||||
let reduced = Scalar([216, 154, 179, 139, 210, 121, 2, 71,
|
||||
69, 99, 158, 216, 23, 173, 63, 100,
|
||||
204, 0, 91, 50, 219, 153, 57, 249,
|
||||
28, 82, 31, 197, 100, 165, 192, 8]);
|
||||
let test_red = Scalar::reduce(&bignum);
|
||||
for i in 0..32 {
|
||||
assert!(test_red[i] == reduced[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
68
src/util.rs
Normal file
68
src/util.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// -*- mode: rust; -*-
|
||||
//
|
||||
// To the extent possible under law, the authors have waived all copyright and
|
||||
// related or neighboring rights to curve25519-dalek, using the Creative
|
||||
// Commons "CC0" public domain dedication. See
|
||||
// <http://creativecommons.org/publicdomain/zero/.0/> for full details.
|
||||
//
|
||||
// Authors:
|
||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||
|
||||
//! Utility functions and tools for constant-time comparisons.
|
||||
|
||||
/// Check equality of two bytes in constant time.
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// Returns 1 if `a == b` and 0 otherwise.
|
||||
#[inline(always)]
|
||||
pub fn bytes_equal_ct(a: u8, b: u8) -> u8 {
|
||||
let mut x: u8;
|
||||
|
||||
x = !(a ^ b);
|
||||
x &= x >> 4;
|
||||
x &= x >> 2;
|
||||
x &= x >> 1;
|
||||
x
|
||||
}
|
||||
|
||||
/// Test if a byte is non-zero in constant time.
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// let mut x: u8;
|
||||
/// x = 0;
|
||||
/// assert!(byte_is_nonzero(x));
|
||||
/// x = 3;
|
||||
/// assert!(byte_is_nonzero(x) == 1);
|
||||
/// ```
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// * If b != 0, returns 1u8.
|
||||
/// * If b == 0, returns 0u8.
|
||||
#[inline(always)]
|
||||
pub fn byte_is_nonzero(b: u8) -> u8 {
|
||||
let mut x = b;
|
||||
x |= x >> 4;
|
||||
x |= x >> 2;
|
||||
x |= x >> 1;
|
||||
(x & 1)
|
||||
}
|
||||
|
||||
/// Check equality of two 32-byte arrays in constant time.
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// Returns 1 if `a == b` and 0 otherwise.
|
||||
#[inline(always)]
|
||||
// We don't use this in curve25519-dalek, but it's useful for e.g. an ed25519 implementation.
|
||||
#[allow(dead_code)]
|
||||
pub fn arrays_equal_ct(a: &[u8; 32], b: &[u8; 32]) -> u8 {
|
||||
let mut x: u8 = 0;
|
||||
|
||||
for i in 0..32 {
|
||||
x |= a[i] ^ b[i];
|
||||
}
|
||||
bytes_equal_ct(x, 0)
|
||||
}
|
||||
Loading…
Reference in a new issue