Compare commits
7 Commits
variable_c
...
explicit_s
| Author | SHA1 | Date | |
|---|---|---|---|
| 6418c323ad | |||
| c14fa90c4a | |||
| 52103991d7 | |||
| 49b2c92d87 | |||
| 02aa03ca5c | |||
| 9594a40d32 | |||
| 10a46a7e81 |
14
.gitignore
vendored
14
.gitignore
vendored
@@ -11,17 +11,3 @@ Cargo.lock
|
||||
|
||||
# And these are just annoying
|
||||
.DS_Store
|
||||
|
||||
# And some Haskell stuff, because I can't shake it!
|
||||
**/cabal.sandbox.config
|
||||
**/.cabal-sandbox
|
||||
|
||||
# Test generation leavings
|
||||
**/*.hi
|
||||
**/*.o
|
||||
**/gen
|
||||
**/*.class
|
||||
**/*.jar
|
||||
|
||||
# And I started playing with IDEs, so ...
|
||||
.vscode
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
script:
|
||||
- cargo build --verbose
|
||||
- travis_wait 25 cargo test --verbose
|
||||
|
||||
@@ -9,10 +9,9 @@ license-file = "LICENSE"
|
||||
repository = "https://github.com/acw/simple_crypto"
|
||||
|
||||
[dependencies]
|
||||
base64 = "^0.9.1"
|
||||
byteorder = "^1.2.1"
|
||||
digest = "^0.7.1"
|
||||
hmac = "^0.5.0"
|
||||
num = "^0.1.42"
|
||||
num = "^0.1.39"
|
||||
rand = "^0.3"
|
||||
sha-1 = "^0.7.0"
|
||||
sha2 = "^0.7.0"
|
||||
|
||||
70
src/cryptonum/arithmetic_traits.rs
Normal file
70
src/cryptonum/arithmetic_traits.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
macro_rules! define_arithmetic {
|
||||
($type: ident, $asncl: ident, $asnfn: ident,
|
||||
$cl: ident, $clfn: ident,
|
||||
$self: ident, $o: ident, $body: block) =>
|
||||
{
|
||||
build_assign_operator!($type, $asncl, $asnfn, $self, $o, $body);
|
||||
derive_arithmetic_operators!($type, $cl, $clfn, $asncl, $asnfn);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! build_assign_operator {
|
||||
($type: ident, $asncl: ident, $asnfn: ident, $self: ident,
|
||||
$o: ident, $body: block) =>
|
||||
{
|
||||
impl<'a> $asncl<&'a $type> for $type {
|
||||
fn $asnfn(&mut $self, $o: &$type) $body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! derive_arithmetic_operators
|
||||
{
|
||||
($type: ident, $cl: ident, $fn: ident, $asncl: ident, $asnfn: ident) => {
|
||||
impl $asncl for $type {
|
||||
fn $asnfn(&mut self, other: $type) {
|
||||
self.$asnfn(&other)
|
||||
}
|
||||
}
|
||||
|
||||
impl $cl for $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, other: $type) -> $type {
|
||||
let mut res = self.clone();
|
||||
res.$asnfn(&other);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $cl<&'a $type> for $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, other: &$type) -> $type {
|
||||
let mut res = self.clone();
|
||||
res.$asnfn(other);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $cl<$type> for &'a $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, other: $type) -> $type {
|
||||
let mut res = self.clone();
|
||||
res.$asnfn(&other);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> $cl<&'a $type> for &'b $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, other: &$type) -> $type {
|
||||
let mut res = self.clone();
|
||||
res.$asnfn(other);
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
112
src/cryptonum/barrett.rs
Normal file
112
src/cryptonum/barrett.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
macro_rules! derive_barrett
|
||||
{
|
||||
($type: ident, $barrett: ident, $count: expr) => {
|
||||
impl CryptoNumFastMod for $type {
|
||||
type BarrettMu = $barrett;
|
||||
|
||||
fn barrett_mu(&self) -> Option<$barrett> {
|
||||
// Step #0: Don't divide by 0.
|
||||
if self.is_zero() {
|
||||
return None
|
||||
}
|
||||
// Step #1: Compute k.
|
||||
let mut k = $count;
|
||||
while self.contents[k - 1] == 0 { k -= 1 };
|
||||
// Step #2: The algorithm below only works if x has at most 2k
|
||||
// digits, so if k*2 < count, abort this whole process.
|
||||
if (k * 2) < $count {
|
||||
return None
|
||||
}
|
||||
// Step #2: Compute floor(b^2k / m), where m is this value.
|
||||
let mut widebody_b2k = [0; ($count * 2) + 1];
|
||||
let mut widebody_self = [0; ($count * 2) + 1];
|
||||
let mut quotient = [0; ($count * 2) + 1];
|
||||
let mut remainder = [0; ($count * 2) + 1];
|
||||
widebody_b2k[$count * 2] = 1;
|
||||
for i in 0..k {
|
||||
widebody_self[i] = self.contents[i];
|
||||
}
|
||||
generic_div(&widebody_b2k, &widebody_self,
|
||||
&mut quotient, &mut remainder);
|
||||
let mut result = [0; $count + 1];
|
||||
for (idx, val) in quotient.iter().enumerate() {
|
||||
if idx < ($count + 1) {
|
||||
result[idx] = *val;
|
||||
} else {
|
||||
if quotient[idx] != 0 {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some($barrett{k: k, progenitor: self.clone(), contents: result})
|
||||
}
|
||||
|
||||
fn fastmod(&self, mu: &$barrett) -> $type {
|
||||
// This algorithm is from our friends at the Handbook of
|
||||
// Applied Cryptography, Chapter 14, Algorithm 14.42.
|
||||
// Step #0:
|
||||
// Expand x so that it has the same size as the Barrett
|
||||
// value.
|
||||
let mut x = [0; $count + 1];
|
||||
for i in 0..$count {
|
||||
x[i] = self.contents[i];
|
||||
}
|
||||
// Step #1:
|
||||
// q1 <- floor(x / b^(k-1))
|
||||
let mut q1 = x.clone();
|
||||
generic_shr(&mut q1, &x, 64 * (mu.k - 1));
|
||||
// q2 <- q1 * mu
|
||||
let q2 = expanding_mul(&q1, &mu.contents);
|
||||
// q3 <- floor(q2 / b^(k+1))
|
||||
let mut q3big = q2.clone();
|
||||
generic_shr(&mut q3big, &q2, 64 * (mu.k + 1));
|
||||
let mut q3 = [0; $count + 1];
|
||||
for (idx, val) in q3big.iter().enumerate() {
|
||||
if idx <= $count {
|
||||
q3[idx] = *val;
|
||||
} else {
|
||||
assert_eq!(*val, 0);
|
||||
}
|
||||
}
|
||||
// Step #2:
|
||||
// r1 <- x mod b^(k+1)
|
||||
let mut r1 = x.clone();
|
||||
for i in mu.k..($count+1) {
|
||||
r1[i] = 0;
|
||||
}
|
||||
// r2 <- q3 * m mod b^(k+1)
|
||||
let mut moddedm = [0; $count + 1];
|
||||
for i in 0..mu.k {
|
||||
moddedm[i] = mu.progenitor.contents[i];
|
||||
}
|
||||
let mut r2 = q3.clone();
|
||||
generic_mul(&mut r2, &q3, &moddedm);
|
||||
// r <- r1 - r2
|
||||
let mut r = r1.clone();
|
||||
generic_sub(&mut r, &r2);
|
||||
let is_negative = !ge(&r1, &r2);
|
||||
// Step #3:
|
||||
// if r < 0 then r <- r + b^(k + 1)
|
||||
if is_negative {
|
||||
let mut bk1 = [0; $count + 1];
|
||||
bk1[mu.k] = 1;
|
||||
generic_add(&mut r, &bk1);
|
||||
}
|
||||
// Step #4:
|
||||
// while r >= m do: r <- r - m.
|
||||
while ge(&r, &moddedm) {
|
||||
generic_sub(&mut r, &moddedm);
|
||||
}
|
||||
// Step #5:
|
||||
// return r
|
||||
let mut retval = [0; $count];
|
||||
for i in 0..$count {
|
||||
retval[i] = r[i];
|
||||
}
|
||||
assert_eq!(r[$count], 0);
|
||||
$type{ contents: retval }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1
src/cryptonum/builder.rs
Normal file
1
src/cryptonum/builder.rs
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
macro_rules! derive_arithmetic_operators
|
||||
{
|
||||
($type: ident, $cl: ident, $fn: ident, $asncl: ident, $asnfn: ident) => {
|
||||
impl $asncl for $type {
|
||||
fn $asnfn(&mut self, other: $type) {
|
||||
self.$asnfn(&other)
|
||||
}
|
||||
}
|
||||
|
||||
impl $cl for $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, other: $type) -> $type {
|
||||
let mut res = self.clone();
|
||||
res.$asnfn(&other);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $cl<&'a $type> for $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, other: &$type) -> $type {
|
||||
let mut res = self.clone();
|
||||
res.$asnfn(other);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $cl<$type> for &'a $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, other: $type) -> $type {
|
||||
let mut res = self.clone();
|
||||
res.$asnfn(&other);
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'b> $cl<&'a $type> for &'b $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, other: &$type) -> $type {
|
||||
let mut res = self.clone();
|
||||
res.$asnfn(other);
|
||||
res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! derive_shift_operators
|
||||
{
|
||||
($type: ident, $asncl: ident, $cl: ident,
|
||||
$asnfn: ident, $fn: ident,
|
||||
$base: ident) =>
|
||||
{
|
||||
impl $asncl<$base> for $type {
|
||||
fn $asnfn(&mut self, rhs: $base) {
|
||||
self.$asnfn(rhs as u64);
|
||||
}
|
||||
}
|
||||
|
||||
derive_shifts_from_shift_assign!($type, $asncl, $cl,
|
||||
$asnfn, $fn,
|
||||
$base);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! derive_shifts_from_shift_assign
|
||||
{
|
||||
($type: ident, $asncl: ident, $cl: ident,
|
||||
$asnfn: ident, $fn: ident,
|
||||
$base: ident) =>
|
||||
{
|
||||
impl $cl<$base> for $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, rhs: $base) -> $type {
|
||||
let mut copy = self.clone();
|
||||
copy.$asnfn(rhs as u64);
|
||||
copy
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $cl<$base> for &'a $type {
|
||||
type Output = $type;
|
||||
|
||||
fn $fn(self, rhs: $base) -> $type {
|
||||
let mut copy = self.clone();
|
||||
copy.$asnfn(rhs as u64);
|
||||
copy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! derive_signed_shift_operators
|
||||
{
|
||||
($type: ident, $base: ident, $signed_base: ident) => {
|
||||
impl ShlAssign<$signed_base> for $type {
|
||||
fn shl_assign(&mut self, rhs: $signed_base) {
|
||||
if rhs < 0 {
|
||||
self.shr_assign(-rhs);
|
||||
} else {
|
||||
self.shl_assign(rhs as $base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ShrAssign<$signed_base> for $type {
|
||||
fn shr_assign(&mut self, rhs: $signed_base) {
|
||||
if rhs < 0 {
|
||||
self.shl_assign(-rhs);
|
||||
} else {
|
||||
self.shr_assign(rhs as $base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
derive_shifts_from_shift_assign!($type, ShlAssign, Shl,
|
||||
shl_assign, shl, $signed_base);
|
||||
derive_shifts_from_shift_assign!($type, ShrAssign, Shr,
|
||||
shr_assign, shr, $signed_base);
|
||||
}
|
||||
}
|
||||
@@ -1,85 +1,77 @@
|
||||
macro_rules! define_from
|
||||
macro_rules! generate_unsigned_conversions
|
||||
{
|
||||
($type: ident, $count: expr) => {
|
||||
generate_unsigned_primtype_conversions!($type, u8, $count);
|
||||
generate_unsigned_primtype_conversions!($type, u16, $count);
|
||||
generate_unsigned_primtype_conversions!($type, u32, $count);
|
||||
generate_unsigned_primtype_conversions!($type, u64, $count);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_signed_conversions
|
||||
{
|
||||
($type: ident, $base: ident) => {
|
||||
generate_signed_primtype_conversions!($type, $base, i8, u8);
|
||||
generate_signed_primtype_conversions!($type, $base, i16, u16);
|
||||
generate_signed_primtype_conversions!($type, $base, i32, u32);
|
||||
generate_signed_primtype_conversions!($type, $base, i64, u64);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_unsigned_primtype_conversions
|
||||
{
|
||||
($type: ident, $base: ty, $count: expr) => {
|
||||
generate_from!($type, $base, x, {
|
||||
let mut res = $type{ contents: [0; $count] };
|
||||
res.contents[0] = x as u64;
|
||||
res
|
||||
});
|
||||
generate_into!($type, $base, self, {
|
||||
self.contents[0] as $base
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_signed_primtype_conversions
|
||||
{
|
||||
($type: ident, $untype: ident, $base: ident, $unbase: ident) => {
|
||||
generate_from!($type, $unbase, x, {
|
||||
$type{ negative: false, value: $untype::from(x) }
|
||||
});
|
||||
generate_into!($type, $unbase, self, {
|
||||
self.value.contents[0] as $unbase
|
||||
});
|
||||
generate_from!($type, $base, x, {
|
||||
let neg = x < 0;
|
||||
$type{negative: neg, value: $untype::from(x.abs() as $unbase)}
|
||||
});
|
||||
generate_into!($type, $base, self, {
|
||||
if self.negative {
|
||||
let start = self.value.contents[0] as $unbase;
|
||||
let mask = ($unbase::max_value() - 1) >> 1;
|
||||
let res = (start & mask) as $base;
|
||||
-res
|
||||
} else {
|
||||
self.value.contents[0] as $base
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! generate_from
|
||||
{
|
||||
($type: ident, $base: ty, $x: ident, $body: block) => {
|
||||
impl From<$base> for $type {
|
||||
fn from(x: $base) -> $type {
|
||||
if x == 0 {
|
||||
UCN{ contents: Vec::new() }
|
||||
} else {
|
||||
UCN{ contents: vec![x as u64] }
|
||||
}
|
||||
}
|
||||
fn from($x: $base) -> $type $body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_signed_from
|
||||
macro_rules! generate_into
|
||||
{
|
||||
($type: ident, $base: ident, $uns: ident) => {
|
||||
impl From<$uns> for $type {
|
||||
fn from(x: $uns) -> $type {
|
||||
SCN{ negative: false, value: UCN::from(x) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$base> for $type {
|
||||
fn from(x: $base) -> $type {
|
||||
let neg = x < 0;
|
||||
let absx = x.abs();
|
||||
SCN{ negative: neg, value: UCN::from(absx as $uns) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_into
|
||||
{
|
||||
($type: ident, $base: ident) => {
|
||||
impl<'a> From<&'a $type> for $base {
|
||||
fn from(x: &$type) -> $base {
|
||||
if x.contents.is_empty() {
|
||||
0
|
||||
} else {
|
||||
x.contents[0] as $base
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$type> for $base {
|
||||
fn from(x: $type) -> $base {
|
||||
$base::from(&x)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! define_signed_into
|
||||
{
|
||||
($type: ident, $base: ident, $uns: ident) => {
|
||||
impl<'a> From<&'a $type> for $uns {
|
||||
fn from(x: &$type) -> $uns {
|
||||
let res: $uns = $uns::from(&x.value);
|
||||
if x.negative { 0-res } else { res }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a $type> for $base {
|
||||
fn from(x: &$type) -> $base {
|
||||
let res: $uns = $uns::from(&x.value);
|
||||
if x.negative { (0-res) as $base } else { res as $base }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$type> for $uns {
|
||||
fn from(x: $type) -> $uns {
|
||||
$uns::from(&x)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$type> for $base {
|
||||
fn from(x: $type) -> $base {
|
||||
$base::from(&x)
|
||||
}
|
||||
($type: ident, $base: ty, $self: ident, $body: block) => {
|
||||
impl Into<$base> for $type {
|
||||
fn into($self) -> $base $body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
332
src/cryptonum/core.rs
Normal file
332
src/cryptonum/core.rs
Normal file
@@ -0,0 +1,332 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_cmp(a: &[u64], b: &[u64]) -> Ordering {
|
||||
let mut i = a.len() - 1;
|
||||
|
||||
assert!(a.len() == b.len());
|
||||
loop {
|
||||
match a[i].cmp(&b[i]) {
|
||||
Ordering::Equal if i == 0 =>
|
||||
return Ordering::Equal,
|
||||
Ordering::Equal =>
|
||||
i -= 1,
|
||||
res =>
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn le(a: &[u64], b: &[u64]) -> bool {
|
||||
generic_cmp(a, b) != Ordering::Greater
|
||||
}
|
||||
|
||||
pub fn ge(a: &[u64], b: &[u64]) -> bool {
|
||||
generic_cmp(a, b) != Ordering::Less
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_bitand(a: &mut [u64], b: &[u64]) {
|
||||
let mut i = 0;
|
||||
|
||||
assert!(a.len() == b.len());
|
||||
while i < a.len() {
|
||||
a[i] &= b[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_bitor(a: &mut [u64], b: &[u64]) {
|
||||
let mut i = 0;
|
||||
|
||||
assert!(a.len() == b.len());
|
||||
while i < a.len() {
|
||||
a[i] |= b[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_bitxor(a: &mut [u64], b: &[u64]) {
|
||||
let mut i = 0;
|
||||
|
||||
assert!(a.len() == b.len());
|
||||
while i < a.len() {
|
||||
a[i] ^= b[i];
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_not(a: &mut [u64]) {
|
||||
for x in a.iter_mut() {
|
||||
*x = !*x;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_shl(a: &mut [u64], orig: &[u64], amount: usize) {
|
||||
let digits = amount / 64;
|
||||
let bits = amount % 64;
|
||||
|
||||
assert!(a.len() == orig.len());
|
||||
for i in 0..a.len() {
|
||||
if i < digits {
|
||||
a[i] = 0;
|
||||
} else {
|
||||
let origidx = i - digits;
|
||||
let prev = if origidx == 0 { 0 } else { orig[origidx - 1] };
|
||||
let (carry,_) = if bits == 0 { (0, false) }
|
||||
else { prev.overflowing_shr(64 - bits as u32) };
|
||||
a[i] = (orig[origidx] << bits) | carry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_shr(a: &mut [u64], orig: &[u64], amount: usize) {
|
||||
let digits = amount / 64;
|
||||
let bits = amount % 64;
|
||||
|
||||
assert!(a.len() == orig.len());
|
||||
for i in 0..a.len() {
|
||||
let oldidx = i + digits;
|
||||
let caridx = i + digits + 1;
|
||||
let old = if oldidx >= a.len() { 0 } else { orig[oldidx] };
|
||||
let carry = if caridx >= a.len() { 0 } else { orig[caridx] };
|
||||
let cb = if bits == 0 { 0 } else { carry << (64 - bits) };
|
||||
a[i] = (old >> bits) | cb;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_add(a: &mut [u64], b: &[u64]) {
|
||||
let mut carry = 0;
|
||||
|
||||
assert!(a.len() == b.len());
|
||||
for i in 0..a.len() {
|
||||
let x = a[i] as u128;
|
||||
let y = b[i] as u128;
|
||||
let total = x + y + carry;
|
||||
a[i] = total as u64;
|
||||
carry = total >> 64;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_sub(a: &mut [u64], b: &[u64]) {
|
||||
let mut negated_rhs = b.to_vec();
|
||||
generic_not(&mut negated_rhs);
|
||||
let mut one = Vec::with_capacity(a.len());
|
||||
one.resize(a.len(), 0);
|
||||
one[0] = 1;
|
||||
generic_add(&mut negated_rhs, &one);
|
||||
generic_add(a, &negated_rhs);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_mul(a: &mut [u64], orig: &[u64], b: &[u64]) {
|
||||
assert!(a.len() == orig.len());
|
||||
assert!(a.len() == b.len());
|
||||
assert!(a == orig);
|
||||
|
||||
// Build the output table. This is a little bit awkward because we don't
|
||||
// know how big we're running, but hopefully the compiler is smart enough
|
||||
// to work all this out.
|
||||
let mut table = Vec::with_capacity(a.len());
|
||||
for _ in 0..a.len() {
|
||||
let mut row = Vec::with_capacity(a.len());
|
||||
row.resize(a.len(), 0);
|
||||
table.push(row);
|
||||
}
|
||||
// This uses "simple" grade school techniques to work things out. But,
|
||||
// for reference, consider two 4 digit numbers:
|
||||
//
|
||||
// l0c3 l0c2 l0c1 l0c0 [orig]
|
||||
// x l1c3 l1c2 l1c1 l1c0 [b]
|
||||
// ------------------------------------------------------------
|
||||
// (l0c3*l1c0) (l0c2*l1c0) (l0c1*l1c0) (l0c0*l1c0)
|
||||
// (l0c2*l1c1) (l0c1*l1c1) (l0c0*l1c1)
|
||||
// (l0c1*l1c2) (l0c0*l1c2)
|
||||
// (l0c0*l1c3)
|
||||
// ------------------------------------------------------------
|
||||
// AAAAA BBBBB CCCCC DDDDD
|
||||
for line in 0..a.len() {
|
||||
let maxcol = a.len() - line;
|
||||
for col in 0..maxcol {
|
||||
let left = orig[col] as u128;
|
||||
let right = b[line] as u128;
|
||||
table[line][col + line] = left * right;
|
||||
}
|
||||
}
|
||||
// ripple the carry across each line, ensuring that each entry in the
|
||||
// table is 64-bits
|
||||
for line in 0..a.len() {
|
||||
let mut carry = 0;
|
||||
for col in 0..a.len() {
|
||||
table[line][col] = table[line][col] + carry;
|
||||
carry = table[line][col] >> 64;
|
||||
table[line][col] &= 0xFFFFFFFFFFFFFFFF;
|
||||
}
|
||||
}
|
||||
// now do the final addition across the lines, rippling the carry as
|
||||
// normal
|
||||
let mut carry = 0;
|
||||
for col in 0..a.len() {
|
||||
let mut total = carry;
|
||||
for line in 0..a.len() {
|
||||
total += table[line][col];
|
||||
}
|
||||
a[col] = total as u64;
|
||||
carry = total >> 64;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn expanding_mul(a: &[u64], b: &[u64]) -> Vec<u64> {
|
||||
assert!(a.len() == b.len());
|
||||
// The maximum size of an n x n digit multiplication is 2n digits, so
|
||||
// here's our output array.
|
||||
let mut result = Vec::with_capacity(a.len() * 2);
|
||||
result.resize(a.len() * 2, 0);
|
||||
|
||||
for (base_idx, digit) in b.iter().enumerate() {
|
||||
let mut myrow = Vec::with_capacity(a.len() * 2);
|
||||
let mut carry = 0;
|
||||
|
||||
myrow.resize(a.len() * 2, 0);
|
||||
for (col_idx, digit2) in a.iter().enumerate() {
|
||||
let left = *digit2 as u128;
|
||||
let right = *digit as u128;
|
||||
let combo = (left * right) + carry;
|
||||
|
||||
myrow[base_idx + col_idx] = combo as u64;
|
||||
carry = combo >> 64;
|
||||
}
|
||||
generic_add(&mut result, &myrow);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn generic_div(inx: &[u64], iny: &[u64],
|
||||
outq: &mut [u64], outr: &mut [u64])
|
||||
{
|
||||
assert!(inx.len() == inx.len());
|
||||
assert!(inx.len() == iny.len());
|
||||
assert!(inx.len() == outq.len());
|
||||
assert!(inx.len() == outr.len());
|
||||
// This algorithm is from the Handbook of Applied Cryptography, Chapter 14,
|
||||
// algorithm 14.20. It has a couple assumptions about the inputs, namely that
|
||||
// n >= t >= 1 and y[t] != 0, where n and t refer to the number of digits in
|
||||
// the numbers. Which means that if we used the inputs unmodified, we can't
|
||||
// divide by single-digit numbers.
|
||||
//
|
||||
// To deal with this, we multiply inx and iny by 2^64, so that we push out
|
||||
// t by one.
|
||||
//
|
||||
// In addition, this algorithm starts to go badly when y[t] is very small
|
||||
// and x[n] is very large. Really, really badly. This can be fixed by
|
||||
// insuring that the top bit is set in y[t], which we can achieve by
|
||||
// shifting everyone over a maxiumum of 63 bits.
|
||||
//
|
||||
// What this means is, just for safety, we add a 0 at the beginning and
|
||||
// end of each number.
|
||||
let mut y = iny.to_vec();
|
||||
let mut x = inx.to_vec();
|
||||
y.insert(0,0); y.push(0);
|
||||
x.insert(0,0); x.push(0);
|
||||
// 0. Compute 'n' and 't'
|
||||
let n = x.len() - 1;
|
||||
let mut t = y.len() - 1;
|
||||
while (t > 0) && (y[t] == 0) { t -= 1 }
|
||||
assert!(y[t] != 0); // this is where division by zero will fire
|
||||
// 0.5. Figure out a shift we can do such that the high bit of y[t] is
|
||||
// set, and then shift x and y left by that much.
|
||||
let additional_shift: usize = y[t].leading_zeros() as usize;
|
||||
let origx = x.clone();
|
||||
let origy = y.clone();
|
||||
generic_shl(&mut x, &origx, additional_shift);
|
||||
generic_shl(&mut y, &origy, additional_shift);
|
||||
// 1. For j from 0 to (n - 1) do: q_j <- 0
|
||||
let mut q = Vec::with_capacity(y.len());
|
||||
q.resize(y.len(), 0);
|
||||
for qj in q.iter_mut() { *qj = 0 }
|
||||
// 2. While (x >= yb^(n-t)) do the following:
|
||||
// q_(n-t) <- q_(n-t) + 1
|
||||
// x <- x - yb^(n-t)
|
||||
let mut ybnt = y.clone();
|
||||
generic_shl(&mut ybnt, &y, 64 * (n - t));
|
||||
while ge(&x, &ybnt) {
|
||||
q[n-t] = q[n-t] + 1;
|
||||
generic_sub(&mut x, &ybnt);
|
||||
}
|
||||
// 3. For i from n down to (t + 1) do the following:
|
||||
let mut i = n;
|
||||
while i >= (t + 1) {
|
||||
// 3.1. if x_i = y_t, then set q_(i-t-1) <- b - 1; otherwise set
|
||||
// q_(i-t-1) <- floor((x_i * b + x_(i-1)) / y_t).
|
||||
if x[i] == y[t] {
|
||||
q[i-t-1] = 0xFFFFFFFFFFFFFFFF;
|
||||
} else {
|
||||
let top = ((x[i] as u128) << 64) + (x[i-1] as u128);
|
||||
let bot = y[t] as u128;
|
||||
let solution = top / bot;
|
||||
q[i-t-1] = solution as u64;
|
||||
}
|
||||
// 3.2. While (q_(i-t-1)(y_t * b + y_(t-1)) > x_i(b2) + x_(i-1)b +
|
||||
// x_(i-2)) do:
|
||||
// q_(i - t - 1) <- q_(i - t 1) - 1.
|
||||
loop {
|
||||
let mut left = Vec::with_capacity(x.len());
|
||||
left.resize(x.len(), 0);
|
||||
left[0] = q[i - t - 1];
|
||||
let mut leftright = Vec::with_capacity(x.len());
|
||||
leftright.resize(x.len(), 0);
|
||||
leftright[0] = y[t-1];
|
||||
|
||||
let copy = left.clone();
|
||||
generic_mul(&mut left, ©, &leftright);
|
||||
let mut right = Vec::with_capacity(x.len());
|
||||
right.resize(x.len(), 0);
|
||||
right[0] = x[i-2];
|
||||
right[1] = x[i-1];
|
||||
right[2] = x[i];
|
||||
|
||||
if le(&left, &right) {
|
||||
break
|
||||
}
|
||||
|
||||
q[i - t - 1] -= 1;
|
||||
}
|
||||
// 3.3. x <- x - q_(i - t - 1) * y * b^(i-t-1)
|
||||
let mut right = Vec::with_capacity(y.len());
|
||||
right.resize(y.len(), 0);
|
||||
right[i - t - 1] = q[i - t - 1];
|
||||
let rightclone = right.clone();
|
||||
generic_mul(&mut right, &rightclone, &y);
|
||||
let wentnegative = generic_cmp(&x, &right) == Ordering::Less;
|
||||
generic_sub(&mut x, &right);
|
||||
// 3.4. if x < 0 then set x <- x + yb^(i-t-1) and
|
||||
// q_(i-t-1) <- q_(i-t-1) - 1
|
||||
if wentnegative {
|
||||
let mut ybit1 = y.to_vec();
|
||||
generic_shl(&mut ybit1, &y, 64 * (i - t - 1));
|
||||
generic_add(&mut x, &ybit1);
|
||||
q[i - t - 1] -= 1;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
// 4. r <- x
|
||||
let finalx = x.clone();
|
||||
generic_shr(&mut x, &finalx, additional_shift);
|
||||
for i in 0..outr.len() {
|
||||
outr[i] = x[i + 1]; // note that for the remainder, we're dividing by
|
||||
// our normalization value.
|
||||
}
|
||||
// 5. return (q,r)
|
||||
for i in 0..outq.len() {
|
||||
outq[i] = q[i];
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
use cryptonum::unsigned::BarrettUCN;
|
||||
use testing::{make_signed,make_unsigned,run_test};
|
||||
|
||||
#[test]
|
||||
fn unsigned_sum_test()
|
||||
{
|
||||
run_test("tests/math/unsigned_add.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
let res = x + y;
|
||||
assert_eq!(res, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_sum_test()
|
||||
{
|
||||
run_test("tests/math/signed_add.tests", 3, |bcase| {
|
||||
let case = make_signed(bcase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x + y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsigned_sub_test()
|
||||
{
|
||||
run_test("tests/math/unsigned_sub.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x - y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_sub_test()
|
||||
{
|
||||
run_test("tests/math/signed_sub.tests", 3, |bcase| {
|
||||
let case = make_signed(bcase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x - y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsigned_mul_test()
|
||||
{
|
||||
run_test("tests/math/unsigned_mul.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x * y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_mul_test()
|
||||
{
|
||||
run_test("tests/math/signed_mul.tests", 3, |bcase| {
|
||||
let case = make_signed(bcase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x * y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsigned_div_test()
|
||||
{
|
||||
run_test("tests/math/unsigned_div.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x / y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_div_test()
|
||||
{
|
||||
run_test("tests/math/signed_div.tests", 3, |bcase| {
|
||||
let case = make_signed(bcase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x / y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unsigned_mod_test()
|
||||
{
|
||||
run_test("tests/math/unsigned_mod.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x % y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signed_mod_test()
|
||||
{
|
||||
run_test("tests/math/signed_mod.tests", 3, |bcase| {
|
||||
let case = make_signed(bcase);
|
||||
let x = case.get("x").unwrap();
|
||||
let y = case.get("y").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(x % y, *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn modular_exponentiation_test()
|
||||
{
|
||||
run_test("tests/math/modexp.tests", 4, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let a = case.get("a").unwrap();
|
||||
let b = case.get("b").unwrap();
|
||||
let m = case.get("m").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
assert_eq!(a.modexp(&b, &m), *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fast_modular_exponentiation_test()
|
||||
{
|
||||
run_test("tests/math/fastmodexp.tests", 6, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let a = case.get("a").unwrap();
|
||||
let b = case.get("b").unwrap();
|
||||
let kbig = case.get("k").unwrap();
|
||||
let k = usize::from(kbig);
|
||||
let m = case.get("m").unwrap();
|
||||
let u = case.get("u").unwrap();
|
||||
let z = case.get("z").unwrap();
|
||||
let mu = BarrettUCN{ k: k, u: u.clone(), m: m.clone() };
|
||||
assert_eq!(a.fastmodexp(&b, &mu), *z);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn barrett_reduction_test()
|
||||
{
|
||||
run_test("tests/math/barrett.tests", 5, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let kbig = case.get("k").unwrap();
|
||||
let m = case.get("m").unwrap();
|
||||
let r = case.get("r").unwrap();
|
||||
let u = case.get("u").unwrap();
|
||||
let v = case.get("v").unwrap();
|
||||
let k = usize::from(kbig);
|
||||
let barrett = m.barrett_u();
|
||||
let result = v.reduce(&barrett);
|
||||
assert_eq!(barrett.k, k);
|
||||
assert_eq!(&barrett.u, u);
|
||||
assert_eq!(&barrett.m, m);
|
||||
assert_eq!(&result, r);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modular_inverse_test()
|
||||
{
|
||||
run_test("tests/math/modinv.tests", 3, |scase| {
|
||||
let case = make_unsigned(scase);
|
||||
let a = case.get("x").unwrap();
|
||||
let m = case.get("y").unwrap();
|
||||
let r = case.get("z").unwrap();
|
||||
let result = a.modinv(m);
|
||||
assert_eq!(r, &result);
|
||||
});
|
||||
}
|
||||
@@ -1,13 +1,63 @@
|
||||
//! # Simple-Crypto CryptoNum
|
||||
//!
|
||||
//! This module is designed to provide large, fixed-width number support for
|
||||
//! the rest of the Simple-Crypto libraries. Feel free to use it other places,
|
||||
//! of course, but that's its origin.
|
||||
//!
|
||||
//! Key generation is supported, using either the native `OsRng` or a random
|
||||
//! number generator of your choice. Obviously, you should be careful to use
|
||||
//! a cryptographically-sound random number generator sufficient for the
|
||||
//! security level you're going for.
|
||||
//!
|
||||
//! Signing and verification are via standard PKCS1 padding, but can be
|
||||
//! adjusted based on the exact hash you want. This library also supports
|
||||
//! somewhat arbitrary signing mechanisms used by your weirder network
|
||||
//! protocols. (I'm looking at you, Tor.)
|
||||
//!
|
||||
//! Encryption and decryption are via the OAEP mechanism, as described in
|
||||
//! NIST documents.
|
||||
//!
|
||||
#[macro_use]
|
||||
mod arithmetic_traits;
|
||||
#[macro_use]
|
||||
mod barrett;
|
||||
#[macro_use]
|
||||
mod conversions;
|
||||
mod core;
|
||||
#[macro_use]
|
||||
mod modops;
|
||||
#[macro_use]
|
||||
mod complete_arith;
|
||||
mod primes;
|
||||
#[macro_use]
|
||||
mod signed;
|
||||
#[macro_use]
|
||||
mod unsigned;
|
||||
#[cfg(test)]
|
||||
mod gold_tests;
|
||||
mod traits;
|
||||
|
||||
use cryptonum::core::*;
|
||||
use num::{BigUint,BigInt};
|
||||
use rand::Rng;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{Debug,Error,Formatter};
|
||||
use std::ops::*;
|
||||
pub use self::traits::*;
|
||||
use self::primes::SMALL_PRIMES;
|
||||
|
||||
construct_unsigned!(U512, BarretMu512, u512, 8);
|
||||
construct_unsigned!(U1024, BarretMu1024, u1024, 16);
|
||||
construct_unsigned!(U2048, BarretMu2048, u2048, 32);
|
||||
construct_unsigned!(U3072, BarretMu3072, u3072, 48);
|
||||
construct_unsigned!(U4096, BarretMu4096, u4096, 64);
|
||||
construct_unsigned!(U7680, BarretMu7680, u7680, 120);
|
||||
construct_unsigned!(U8192, BarretMu8192, u8192, 128);
|
||||
construct_unsigned!(U15360, BarretMu15360, u15360, 240);
|
||||
|
||||
construct_signed!(I512, U512, i512);
|
||||
construct_signed!(I1024, U1024, i1024);
|
||||
construct_signed!(I2048, U2048, i2048);
|
||||
construct_signed!(I3072, U3072, i3072);
|
||||
construct_signed!(I4096, U4096, i4096);
|
||||
construct_signed!(I7680, U7680, i7680);
|
||||
construct_signed!(I8192, U8192, i8192);
|
||||
construct_signed!(I15360, U15360, i15360);
|
||||
|
||||
pub use self::signed::SCN;
|
||||
pub use self::unsigned::{BarrettUCN,UCN};
|
||||
pub use self::primes::*;
|
||||
|
||||
16
src/cryptonum/modops.rs
Normal file
16
src/cryptonum/modops.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
macro_rules! derive_modulo_operations
|
||||
{
|
||||
($type: ident) => {
|
||||
impl CryptoNumModOps for $type {
|
||||
fn modinv(&self, _b: &Self) -> Self {
|
||||
panic!("modinv");
|
||||
}
|
||||
fn modexp(&self, _a: &Self, _b: &Self) -> Self {
|
||||
panic!("modexp");
|
||||
}
|
||||
fn modsq(&self, _v: &Self) -> Self {
|
||||
panic!("modsq");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
use cryptonum::unsigned::UCN;
|
||||
use rand::Rng;
|
||||
|
||||
static SMALL_PRIMES: [u32; 310] = [
|
||||
pub static SMALL_PRIMES: [u32; 310] = [
|
||||
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
|
||||
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
||||
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
|
||||
@@ -34,106 +31,89 @@ static SMALL_PRIMES: [u32; 310] = [
|
||||
1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
|
||||
1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053];
|
||||
|
||||
macro_rules! derive_prime_operations
|
||||
{
|
||||
($type: ident, $count: expr) => {
|
||||
impl $type {
|
||||
fn miller_rabin<G: Rng>(&self, g: &mut G, iters: usize)
|
||||
-> bool
|
||||
{
|
||||
let nm1 = self - $type::from(1 as u8);
|
||||
// Quoth Wikipedia:
|
||||
// write n - 1 as 2^r*d with d odd by factoring powers of 2 from n - 1
|
||||
let mut d = nm1.clone();
|
||||
let mut r = 0;
|
||||
while d.is_even() {
|
||||
d >>= 1;
|
||||
r += 1;
|
||||
assert!(r < ($count * 64));
|
||||
}
|
||||
// WitnessLoop: repeat k times
|
||||
'WitnessLoop: for _k in 0..iters {
|
||||
// pick a random integer a in the range [2, n - 2]
|
||||
let a = $type::random_in_range(g, &$type::from(2 as u8), &nm1);
|
||||
// x <- a^d mod n
|
||||
let mut x = a.modexp(&d, &self);
|
||||
// if x = 1 or x = n - 1 then
|
||||
if (&x == &$type::from(1 as u8)) || (&x == &nm1) {
|
||||
// continue WitnessLoop
|
||||
continue 'WitnessLoop;
|
||||
}
|
||||
// repeat r - 1 times:
|
||||
for _i in 0..r {
|
||||
// x <- x^2 mod n
|
||||
x = x.modexp(&$type::from(2 as u8), &self);
|
||||
// if x = 1 then
|
||||
if &x == &$type::from(1 as u8) {
|
||||
// return composite
|
||||
return false;
|
||||
}
|
||||
// if x = n - 1 then
|
||||
if &x == &nm1 {
|
||||
// continue WitnessLoop
|
||||
continue 'WitnessLoop;
|
||||
}
|
||||
}
|
||||
// return composite
|
||||
return false;
|
||||
}
|
||||
// return probably prime
|
||||
true
|
||||
}
|
||||
|
||||
impl UCN {
|
||||
pub fn generate_prime<F,G>(rng: &mut G,
|
||||
bitlen: usize,
|
||||
iterations: usize,
|
||||
check_value: F)
|
||||
-> UCN
|
||||
where
|
||||
G: Rng,
|
||||
F: Fn(UCN) -> Option<UCN>
|
||||
{
|
||||
let one = UCN::from(1 as u8);
|
||||
|
||||
assert!((bitlen % 64) == 0);
|
||||
loop {
|
||||
let base = random_number(rng, bitlen);
|
||||
let candidate = base | &one;
|
||||
|
||||
if let Some(proposed) = check_value(candidate) {
|
||||
if proposed.probably_prime(rng, bitlen, iterations) {
|
||||
return proposed;
|
||||
fn random_in_range<G: Rng>(rng: &mut G, min: &$type, max: &$type)
|
||||
-> $type
|
||||
{
|
||||
loop {
|
||||
let candidate = $type::random_number(rng);
|
||||
if (&candidate >= min) && (&candidate < max) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn probably_prime<G: Rng>(&self, g: &mut G, size: usize, iters: usize)
|
||||
-> bool
|
||||
{
|
||||
for tester in SMALL_PRIMES.iter() {
|
||||
if (self % UCN::from(*tester)).is_zero() {
|
||||
return false;
|
||||
fn random_number<G: Rng>(rng: &mut G) -> $type {
|
||||
let mut components = [0; $count];
|
||||
for i in 0..$count {
|
||||
components[i] = rng.gen();
|
||||
}
|
||||
$type{ contents: components }
|
||||
}
|
||||
}
|
||||
miller_rabin(g, &self, size, iters)
|
||||
}
|
||||
}
|
||||
|
||||
fn miller_rabin<G: Rng>(g: &mut G, n: &UCN, size: usize, iters: usize) -> bool {
|
||||
let one = UCN::from(1 as u8);
|
||||
let two = UCN::from(2 as u8);
|
||||
let nm1 = n - &one;
|
||||
// Quoth Wikipedia:
|
||||
// write n - 1 as 2^r*d with d odd by factoring powers of 2 from n - 1
|
||||
let mut d = nm1.clone();
|
||||
let mut r = 0;
|
||||
while d.is_even() {
|
||||
d >>= 1;
|
||||
r += 1;
|
||||
assert!(r < n.bits());
|
||||
}
|
||||
// WitnessLoop: repeat k times
|
||||
'WitnessLoop: for _k in 0..iters {
|
||||
// pick a random integer a in the range [2, n - 2]
|
||||
let a = random_in_range(g, size, &two, &nm1);
|
||||
// x <- a^d mod n
|
||||
let mut x = a.modexp(&d, &n);
|
||||
// if x = 1 or x = n - 1 then
|
||||
if (&x == &one) || (&x == &nm1) {
|
||||
// continue WitnessLoop
|
||||
continue 'WitnessLoop;
|
||||
}
|
||||
// repeat r - 1 times:
|
||||
for _i in 0..r {
|
||||
// x <- x^2 mod n
|
||||
x = x.modexp(&two, &n);
|
||||
// if x = 1 then
|
||||
if &x == &one {
|
||||
// return composite
|
||||
return false;
|
||||
impl CryptoNumPrimes for $type {
|
||||
fn probably_prime<G: Rng>(&self, g: &mut G, iters: usize) -> bool {
|
||||
for tester in SMALL_PRIMES.iter() {
|
||||
let testvalue = $type::from(*tester);
|
||||
if (self % testvalue).is_zero() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.miller_rabin(g, iters)
|
||||
}
|
||||
// if x = n - 1 then
|
||||
if &x == &nm1 {
|
||||
// continue WitnessLoop
|
||||
continue 'WitnessLoop;
|
||||
fn generate_prime<G: Rng>(_g: &mut G, _iters: usize, _e: &Self, _min: &Self) -> Self {
|
||||
panic!("generate_prime");
|
||||
}
|
||||
}
|
||||
// return composite
|
||||
return false;
|
||||
}
|
||||
// return probably prime
|
||||
true
|
||||
}
|
||||
|
||||
fn random_in_range<G: Rng>(rng: &mut G, bitlen: usize, min: &UCN, max: &UCN)
|
||||
-> UCN
|
||||
{
|
||||
loop {
|
||||
let candidate = random_number(rng, bitlen);
|
||||
|
||||
if (&candidate >= min) && (&candidate < max) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn random_number<G: Rng>(rng: &mut G, bitlen: usize) -> UCN {
|
||||
assert!(bitlen % 64 == 0);
|
||||
let wordlen = bitlen / 64;
|
||||
let components = rng.gen_iter().take(wordlen).collect();
|
||||
UCN{ contents: components }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,406 +1,237 @@
|
||||
use cryptonum::unsigned::{BarrettUCN,UCN,divmod};
|
||||
use num::BigInt;
|
||||
use num::bigint::Sign;
|
||||
use std::fmt;
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::Write;
|
||||
use std::ops::*;
|
||||
|
||||
/// In case you were wondering, it stands for "Signed Crypto Num".
|
||||
#[derive(Clone,Debug,PartialEq,Eq)]
|
||||
pub struct SCN {
|
||||
pub(crate) negative: bool,
|
||||
pub(crate) value: UCN
|
||||
}
|
||||
|
||||
impl SCN {
|
||||
pub fn zero() -> SCN {
|
||||
SCN{ negative: false, value: UCN::zero() }
|
||||
}
|
||||
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.value.is_zero()
|
||||
}
|
||||
|
||||
pub fn is_negative(&self) -> bool {
|
||||
self.negative
|
||||
}
|
||||
|
||||
pub fn from_str(x: &str) -> SCN {
|
||||
if x.get(0..1) == Some("-") {
|
||||
SCN{ negative: true, value: UCN::from_str(&x[1..]) }
|
||||
} else {
|
||||
SCN{ negative: false, value: UCN::from_str(x) }
|
||||
}
|
||||
}
|
||||
|
||||
fn cleanup(&mut self) {
|
||||
if self.value.is_zero() {
|
||||
self.negative = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn egcd(self, b: SCN) -> (SCN, SCN, SCN) {
|
||||
let mut s = SCN::zero();
|
||||
let mut old_s = SCN::from(1 as u8);
|
||||
let mut t = SCN::from(1 as u8);
|
||||
let mut old_t = SCN::zero();
|
||||
let mut r = b;
|
||||
let mut old_r = self;
|
||||
|
||||
while !r.is_zero() {
|
||||
let quotient = old_r.clone() / r.clone();
|
||||
|
||||
let prov_r = r.clone();
|
||||
let prov_s = s.clone();
|
||||
let prov_t = t.clone();
|
||||
|
||||
r = old_r - (r * "ient);
|
||||
s = old_s - (s * "ient);
|
||||
t = old_t - (t * "ient);
|
||||
|
||||
old_r = prov_r;
|
||||
old_s = prov_s;
|
||||
old_t = prov_t;
|
||||
macro_rules! construct_signed {
|
||||
($type: ident, $base: ident, $modname: ident) => {
|
||||
#[derive(Clone,PartialEq,Eq)]
|
||||
pub struct $type {
|
||||
negative: bool,
|
||||
value: $base
|
||||
}
|
||||
|
||||
(old_r, old_s, old_t)
|
||||
}
|
||||
|
||||
pub fn reduce(&self, m: &BarrettUCN) -> SCN {
|
||||
println!("signed reduce");
|
||||
SCN{ negative: false, value: self.value.reduce(m) }
|
||||
}
|
||||
|
||||
pub fn divmod(&self, x: &SCN, m: &BarrettUCN) -> SCN {
|
||||
println!("STEP1");
|
||||
let xmod = x.reduce(m);
|
||||
println!("STEP2");
|
||||
assert!(!xmod.negative);
|
||||
println!("STEP3");
|
||||
let i = xmod.value.modinv(&m.m);
|
||||
println!("STEP4");
|
||||
let si = SCN::from(i);
|
||||
println!("STEP5");
|
||||
let yi = self * si;
|
||||
println!("STEP6: {:X}", yi);
|
||||
println!(" mod {:X}", m.m);
|
||||
let res = yi.reduce(m);
|
||||
println!("STEP7");
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::UpperHex for SCN {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(),fmt::Error> {
|
||||
if self.negative {
|
||||
fmt.write_char('-')?;
|
||||
}
|
||||
self.value.fmt(fmt)
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Conversions to/from crypto nums.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
define_signed_from!(SCN, i8, u8);
|
||||
define_signed_from!(SCN, i16, u16);
|
||||
define_signed_from!(SCN, i32, u32);
|
||||
define_signed_from!(SCN, i64, u64);
|
||||
define_signed_into!(SCN, i8, u8);
|
||||
define_signed_into!(SCN, i16, u16);
|
||||
define_signed_into!(SCN, i32, u32);
|
||||
define_signed_into!(SCN, i64, u64);
|
||||
|
||||
impl From<UCN> for SCN {
|
||||
fn from(x: UCN) -> SCN {
|
||||
SCN{ negative: false, value: x }
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<UCN> for SCN {
|
||||
fn into(self) -> UCN {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SCN> for BigInt {
|
||||
fn from(x: SCN) -> BigInt {
|
||||
let sign = if x.is_negative() { Sign::Minus } else { Sign::Plus };
|
||||
let numbytes = x.value.contents.len() * 8;
|
||||
let bytes = x.value.to_bytes(numbytes);
|
||||
BigInt::from_bytes_be(sign, &bytes)
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Comparisons
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
impl PartialOrd for SCN {
|
||||
fn partial_cmp(&self, other: &SCN) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for SCN {
|
||||
fn cmp(&self, other: &SCN) -> Ordering {
|
||||
match (self.negative, other.negative) {
|
||||
(false, false) => self.value.cmp(&other.value),
|
||||
(false, true) => Ordering::Greater,
|
||||
(true, false) => Ordering::Less,
|
||||
(true, true) => self.value.cmp(&other.value).reverse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Shifts
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
impl ShlAssign<u64> for SCN {
|
||||
fn shl_assign(&mut self, rhs: u64) {
|
||||
self.value <<= rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Shl<u64> for SCN {
|
||||
type Output = SCN;
|
||||
|
||||
fn shl(self, rhs: u64) -> SCN {
|
||||
let mut copy = self.clone();
|
||||
copy.shl_assign(rhs);
|
||||
copy
|
||||
}
|
||||
}
|
||||
|
||||
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, usize);
|
||||
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u32);
|
||||
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u16);
|
||||
derive_shift_operators!(SCN, ShlAssign, Shl, shl_assign, shl, u8);
|
||||
|
||||
impl ShrAssign<u64> for SCN {
|
||||
fn shr_assign(&mut self, rhs: u64) {
|
||||
self.value >>= rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Shr<u64> for SCN {
|
||||
type Output = SCN;
|
||||
|
||||
fn shr(self, rhs: u64) -> SCN {
|
||||
let mut copy = self.clone();
|
||||
copy.shr_assign(rhs);
|
||||
copy
|
||||
}
|
||||
}
|
||||
|
||||
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, usize);
|
||||
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u32);
|
||||
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u16);
|
||||
derive_shift_operators!(SCN, ShrAssign, Shr, shr_assign, shr, u8);
|
||||
|
||||
derive_signed_shift_operators!(SCN, usize, isize);
|
||||
derive_signed_shift_operators!(SCN, u64, i64);
|
||||
derive_signed_shift_operators!(SCN, u32, i32);
|
||||
derive_signed_shift_operators!(SCN, u16, i16);
|
||||
derive_signed_shift_operators!(SCN, u8, i8);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Arithmetic
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
impl Neg for SCN {
|
||||
type Output = SCN;
|
||||
|
||||
fn neg(self) -> SCN {
|
||||
if self.is_zero() {
|
||||
self
|
||||
} else {
|
||||
SCN{ negative: !self.negative, value: self.value }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a SCN {
|
||||
type Output = SCN;
|
||||
|
||||
fn neg(self) -> SCN {
|
||||
if self.is_zero() {
|
||||
self.clone()
|
||||
} else {
|
||||
SCN{ negative: !self.negative, value: self.value.clone() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AddAssign<&'a SCN> for SCN {
|
||||
fn add_assign(&mut self, rhs: &SCN) {
|
||||
if self.negative == rhs.negative {
|
||||
self.value.add_assign(&rhs.value);
|
||||
} else {
|
||||
if self.value >= rhs.value {
|
||||
self.value.sub_assign(&rhs.value);
|
||||
} else {
|
||||
self.negative = !self.negative;
|
||||
self.value = &rhs.value - &self.value;
|
||||
impl Debug for $type {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(),Error> {
|
||||
if self.negative {
|
||||
f.write_str("-")?;
|
||||
} else {
|
||||
f.write_str("+")?;
|
||||
}
|
||||
self.value.fmt(f)
|
||||
}
|
||||
}
|
||||
self.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SubAssign<&'a SCN> for SCN {
|
||||
fn sub_assign(&mut self, rhs: &SCN) {
|
||||
let flipped = SCN{ negative: !rhs.negative, value: rhs.value.clone() };
|
||||
self.add_assign(&flipped);
|
||||
self.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MulAssign<&'a SCN> for SCN {
|
||||
fn mul_assign(&mut self, rhs: &SCN) {
|
||||
self.negative ^= rhs.negative;
|
||||
self.value.mul_assign(&rhs.value);
|
||||
self.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DivAssign<&'a SCN> for SCN {
|
||||
fn div_assign(&mut self, rhs: &SCN) {
|
||||
self.negative ^= rhs.negative;
|
||||
// rounding makes me grumpy
|
||||
let mut remainder = Vec::new();
|
||||
let copy = self.value.contents.clone();
|
||||
divmod(&mut self.value.contents, &mut remainder,
|
||||
©, &rhs.value.contents);
|
||||
if self.negative && !remainder.is_empty() {
|
||||
let one = UCN{ contents: vec![1] };
|
||||
self.sub_assign(SCN{ negative: false, value: one});
|
||||
}
|
||||
self.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RemAssign<&'a SCN> for SCN {
|
||||
fn rem_assign(&mut self, rhs: &SCN) {
|
||||
let base = &self.value % &rhs.value;
|
||||
|
||||
if self.negative == rhs.negative {
|
||||
self.value = base;
|
||||
} else {
|
||||
self.negative = rhs.negative;
|
||||
self.value = &rhs.value - &base;
|
||||
}
|
||||
self.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
derive_arithmetic_operators!(SCN, Add, add, AddAssign, add_assign);
|
||||
derive_arithmetic_operators!(SCN, Sub, sub, SubAssign, sub_assign);
|
||||
derive_arithmetic_operators!(SCN, Mul, mul, MulAssign, mul_assign);
|
||||
derive_arithmetic_operators!(SCN, Div, div, DivAssign, div_assign);
|
||||
derive_arithmetic_operators!(SCN, Rem, rem, RemAssign, rem_assign);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Tests!
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use super::*;
|
||||
|
||||
impl Arbitrary for SCN {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> SCN {
|
||||
let neg = (g.next_u32() & 1) == 1;
|
||||
SCN{ negative: neg, value: UCN::arbitrary(g) }
|
||||
}
|
||||
}
|
||||
|
||||
fn one() -> SCN {
|
||||
SCN{ negative: false, value: UCN::from(1 as u8) }
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn additive_identity(x: SCN) -> bool {
|
||||
(&x + &SCN::zero()) == x
|
||||
}
|
||||
fn subtractive_identity(x: SCN) -> bool {
|
||||
(&x - &SCN::zero()) == x
|
||||
}
|
||||
fn multiplicative_identity(x: SCN) -> bool {
|
||||
(&x * &one()) == x
|
||||
}
|
||||
fn division_identity(x: SCN) -> bool {
|
||||
let result = &x / &one();
|
||||
result == x
|
||||
impl<'a> PartialEq<&'a $type> for $type {
|
||||
fn eq(&self, other: &&$type) -> bool {
|
||||
(self.negative == other.negative) &&
|
||||
(self.value == other.value)
|
||||
}
|
||||
}
|
||||
|
||||
fn additive_destructor(x: SCN) -> bool {
|
||||
(&x + (- &x)) == SCN::zero()
|
||||
}
|
||||
fn subtractive_destructor(x: SCN) -> bool {
|
||||
(&x - &x) == SCN::zero()
|
||||
}
|
||||
fn multiplicative_destructor(x: SCN) -> bool {
|
||||
(x * SCN::zero()) == SCN::zero()
|
||||
}
|
||||
fn division_deastructor(x: SCN) -> bool {
|
||||
(&x / &x) == one()
|
||||
}
|
||||
fn remainder_destructor(x: SCN) -> bool {
|
||||
(&x % &x) == SCN::zero()
|
||||
impl PartialOrd for $type {
|
||||
fn partial_cmp(&self, other: &$type) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
fn addition_commutes(a: SCN, b: SCN) -> bool {
|
||||
(&a + &b) == (&b + &a)
|
||||
}
|
||||
fn multiplication_commutes(a: SCN, b: SCN) -> bool {
|
||||
(&a * &b) == (&b * &a)
|
||||
}
|
||||
fn addition_associates(a: SCN, b: SCN, c: SCN) -> bool {
|
||||
((&a + &b) + &c) == (&a + (&b + &c))
|
||||
}
|
||||
fn multiplication_associates(a: SCN, b: SCN, c: SCN) -> bool {
|
||||
((&a * &b) * &c) == (&a * (&b * &c))
|
||||
}
|
||||
fn distribution_works(a: SCN, b: SCN, c: SCN) -> bool {
|
||||
(&a * (&b + &c)) == ((&a * &b) + (&a * &c))
|
||||
impl Ord for $type {
|
||||
fn cmp(&self, other: &$type) -> Ordering {
|
||||
match (self.negative, other.negative) {
|
||||
(true, true) =>
|
||||
self.value.cmp(&other.value).reverse(),
|
||||
(true, false) => Ordering::Greater,
|
||||
(false, true) => Ordering::Less,
|
||||
(false, false) =>
|
||||
self.value.cmp(&other.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn negation_works(a: SCN) -> bool {
|
||||
(- &a) == (&a * &SCN{ negative: true, value: UCN::from(1 as u8) })
|
||||
impl CryptoNumBase for $type {
|
||||
fn zero() -> $type {
|
||||
$type{ negative: false, value: $base::zero() }
|
||||
}
|
||||
fn max_value() -> $type {
|
||||
$type{ negative: false, value: $base::max_value() }
|
||||
}
|
||||
fn is_zero(&self) -> bool {
|
||||
self.value.is_zero()
|
||||
}
|
||||
fn is_odd(&self) -> bool {
|
||||
self.value.is_odd()
|
||||
}
|
||||
fn is_even(&self) -> bool {
|
||||
self.value.is_even()
|
||||
}
|
||||
}
|
||||
fn double_negation_works(a: SCN) -> bool {
|
||||
(- (- &a)) == a
|
||||
}
|
||||
fn negation_commutes(a: SCN, b: SCN) -> bool {
|
||||
((- &a) * &b) == (&a * (- &b))
|
||||
}
|
||||
fn negation_cancels(a: SCN, b: SCN) -> bool {
|
||||
((- &a) * (- &b)) == (&a * &b)
|
||||
}
|
||||
fn negation_distributes(a: SCN, b: SCN) -> bool {
|
||||
(- (&a + &b)) == ((- &a) + (- &b))
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn egcd_works(a: SCN, b: SCN) -> bool {
|
||||
let (d, x, y) = a.clone().egcd(b.clone());
|
||||
((a * x) + (b * y)) == d
|
||||
impl CryptoNumFastMod for $type {
|
||||
type BarrettMu = <$base as CryptoNumFastMod>::BarrettMu;
|
||||
|
||||
fn barrett_mu(&self) -> Option<Self::BarrettMu> {
|
||||
if self.negative {
|
||||
None
|
||||
} else {
|
||||
self.value.barrett_mu()
|
||||
}
|
||||
}
|
||||
|
||||
fn fastmod(&self, mu: &Self::BarrettMu) -> $type {
|
||||
let res = self.value.fastmod(mu);
|
||||
$type{ negative: self.negative, value: res }
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoNumSigned for $type {
|
||||
type Unsigned = $base;
|
||||
|
||||
fn new(v: $base) -> $type {
|
||||
$type{ negative: false, value: v.clone() }
|
||||
}
|
||||
fn abs(&self) -> $base {
|
||||
self.value.clone()
|
||||
}
|
||||
fn is_positive(&self) -> bool {
|
||||
!self.negative
|
||||
}
|
||||
fn is_negative(&self) -> bool {
|
||||
self.negative
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for $type {
|
||||
type Output = $type;
|
||||
|
||||
fn neg(self) -> $type {
|
||||
(&self).neg()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Neg for &'a $type {
|
||||
type Output = $type;
|
||||
|
||||
fn neg(self) -> $type {
|
||||
if self.value.is_zero() {
|
||||
$type{ negative: false, value: self.value.clone() }
|
||||
} else {
|
||||
$type{ negative: !self.negative, value: self.value.clone() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
define_arithmetic!($type,AddAssign,add_assign,Add,add,self,other,{
|
||||
let signs_match = self.negative == other.negative;
|
||||
let ordering = self.value.cmp(&other.value);
|
||||
|
||||
match (signs_match, ordering) {
|
||||
(true, _) =>
|
||||
// if the signs are the same, we maintain the sign and
|
||||
// just increase the magnitude
|
||||
self.value.add_assign(&other.value),
|
||||
(false, Ordering::Equal) => {
|
||||
// if the signs are different and the numbers are equal,
|
||||
// we just set this to zero. However, we actually do the
|
||||
// subtraction to make the timing roughly similar.
|
||||
self.negative = false;
|
||||
self.value.sub_assign(&other.value)
|
||||
}
|
||||
(false, Ordering::Less) => {
|
||||
// if the signs are different and the first one is less
|
||||
// than the second, then we flip the sign and subtract.
|
||||
self.negative = !self.negative;
|
||||
let mut other_copy = other.value.clone();
|
||||
other_copy.sub_assign(&self.value);
|
||||
self.value = other_copy;
|
||||
}
|
||||
(false, Ordering::Greater) => {
|
||||
// if the signs are different and the first one is
|
||||
// greater than the second, then we leave the sign and
|
||||
// subtract.
|
||||
self.value.sub_assign(&other.value)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
define_arithmetic!($type,SubAssign,sub_assign,Sub,sub,self,other,{
|
||||
// this is a bit inefficient, but a heck of a lot easier.
|
||||
let mut other2 = other.clone();
|
||||
other2.negative = !other2.negative;
|
||||
self.add_assign(&other2)
|
||||
});
|
||||
|
||||
define_arithmetic!($type,MulAssign,mul_assign,Mul,mul,self,other,{
|
||||
self.negative = self.negative ^ other.negative;
|
||||
self.value.mul_assign(&other.value);
|
||||
});
|
||||
|
||||
define_arithmetic!($type,DivAssign,div_assign,Div,div,self,other,{
|
||||
self.negative = self.negative ^ other.negative;
|
||||
self.value.div_assign(&other.value);
|
||||
});
|
||||
|
||||
define_arithmetic!($type,RemAssign,rem_assign,Rem,rem,self,other,{
|
||||
self.value.rem_assign(&other.value);
|
||||
});
|
||||
|
||||
generate_signed_conversions!($type, $base);
|
||||
|
||||
#[cfg(test)]
|
||||
mod $modname {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use super::*;
|
||||
|
||||
impl Arbitrary for $type {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> $type {
|
||||
let value = $base::arbitrary(g);
|
||||
if value.is_zero() {
|
||||
$type{ negative: false, value: value }
|
||||
} else {
|
||||
$type{ negative: g.gen_weighted_bool(2), value: value }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn double_negation(x: $type) -> bool {
|
||||
(- (- &x)) == &x
|
||||
}
|
||||
fn add_identity(x: $type) -> bool {
|
||||
(&x + $type::zero()) == &x
|
||||
}
|
||||
fn add_commutivity(x: $type, y: $type) -> bool {
|
||||
(&x + &y) == (&y + &x)
|
||||
}
|
||||
fn add_associativity(a: $type, b: $type, c: $type) -> bool {
|
||||
// we shift these to get away from rollover
|
||||
let x = $type{ negative: a.negative, value: a.value >> 2 };
|
||||
let y = $type{ negative: b.negative, value: b.value >> 2 };
|
||||
let z = $type{ negative: c.negative, value: c.value >> 2 };
|
||||
(&x + (&y + &z)) == ((&x + &y) + &z)
|
||||
}
|
||||
fn sub_is_add_negation(x: $type, y: $type) -> bool {
|
||||
(&x - &y) == (&x + (- &y))
|
||||
}
|
||||
fn sub_destroys(x: $type) -> bool {
|
||||
(&x - &x) == $type::zero()
|
||||
}
|
||||
fn mul_identity(x: $type) -> bool {
|
||||
(&x * $type::from(1)) == &x
|
||||
}
|
||||
fn mul_commutivity(x: $type, y: $type) -> bool {
|
||||
(&x * &y) == (&y * &x)
|
||||
}
|
||||
fn mul_associativity(a: $type, b: $type, c: $type) -> bool {
|
||||
// we shift these to get away from rollover
|
||||
let s = (a.value.bit_size() / 2) - 2;
|
||||
let x = $type{ negative: a.negative, value: a.value >> s };
|
||||
let y = $type{ negative: b.negative, value: b.value >> s };
|
||||
let z = $type{ negative: c.negative, value: c.value >> s };
|
||||
(&x * (&y * &z)) == ((&x * &y) * &z)
|
||||
}
|
||||
#[ignore]
|
||||
fn div_identity(a: $type) -> bool {
|
||||
&a / $type::from(1) == a
|
||||
}
|
||||
fn div_self_is_one(a: $type) -> bool {
|
||||
(&a / &a) == $type::from(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
79
src/cryptonum/traits.rs
Normal file
79
src/cryptonum/traits.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use rand::Rng;
|
||||
|
||||
pub trait CryptoNumBase {
|
||||
/// Generate the zero value for this type.
|
||||
fn zero() -> Self;
|
||||
/// Generate the maximum possible value for this type.
|
||||
fn max_value() -> Self;
|
||||
/// Test if the number is zero.
|
||||
fn is_zero(&self) -> bool;
|
||||
/// Test if the number is odd (a.k.a., the low bit is set)
|
||||
fn is_odd(&self) -> bool;
|
||||
/// Test if the number is even (a.k.a., the low bit is clear)
|
||||
fn is_even(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait CryptoNumSerialization {
|
||||
/// The number of bits used when this number is serialized.
|
||||
fn bit_size(&self) -> usize;
|
||||
/// The number of bytes used when this number is serialized.
|
||||
fn byte_size(&self) -> usize;
|
||||
/// Convert a number to a series of bytes, in standard order (most to
|
||||
/// least significant)
|
||||
fn to_bytes(&self) -> Vec<u8>;
|
||||
/// Convert a series of bytes into the number. The size of the given slice
|
||||
/// must be greater than or equal to the size of the number, and must be
|
||||
/// a multiple of 8 bytes long. Unused bytes should be ignored.
|
||||
fn from_bytes(&[u8]) -> Self;
|
||||
}
|
||||
|
||||
pub trait CryptoNumFastMod {
|
||||
/// A related type that can hold the constant required for Barrett
|
||||
/// reduction.
|
||||
type BarrettMu;
|
||||
|
||||
/// Compute the Barett constant mu, using this as a modulus, which we can
|
||||
/// use later to perform faster mod operations.
|
||||
fn barrett_mu(&self) -> Option<Self::BarrettMu>;
|
||||
/// Faster modulo through the use of the Barrett constant, above.
|
||||
fn fastmod(&self, &Self::BarrettMu) -> Self;
|
||||
}
|
||||
|
||||
pub trait CryptoNumSigned {
|
||||
/// The unsigned type that this type is related to.
|
||||
type Unsigned;
|
||||
|
||||
/// Generate a new signed number based on the given unsigned number.
|
||||
fn new(x: Self::Unsigned) -> Self;
|
||||
/// Get the absolute value of the signed number, turning it back into an
|
||||
/// unsigned number.
|
||||
fn abs(&self) -> Self::Unsigned;
|
||||
/// Test if the number is negative.
|
||||
fn is_negative(&self) -> bool;
|
||||
/// Test if the number is positive.
|
||||
fn is_positive(&self) -> bool;
|
||||
}
|
||||
|
||||
pub trait CryptoNumModOps: Sized
|
||||
{
|
||||
/// Compute the modular inverse of the number.
|
||||
fn modinv(&self, b: &Self) -> Self;
|
||||
/// Raise the number to the power of the first value, mod the second.
|
||||
fn modexp(&self, a: &Self, b: &Self) -> Self;
|
||||
/// Square the number, mod the given value.
|
||||
fn modsq(&self, v: &Self) -> Self;
|
||||
}
|
||||
|
||||
pub trait CryptoNumPrimes
|
||||
{
|
||||
/// Determine if the given number is probably prime using a quick spot
|
||||
/// check and Miller-Rabin, using the given random number generator
|
||||
/// and number of iterations.
|
||||
fn probably_prime<G: Rng>(&self, g: &mut G, iters: usize) -> bool;
|
||||
/// Generate a prime using the given random number generator, using
|
||||
/// the given number of rounds to determine if the number is probably
|
||||
/// prime. The other two numbers are a number for which the generator
|
||||
/// should have a GCD of 1, and the minimum value for the number.
|
||||
fn generate_prime<G: Rng>(g: &mut G, iters: usize, e: &Self, min: &Self)
|
||||
-> Self;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,28 +0,0 @@
|
||||
use simple_asn1::ASN1DecodeErr;
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DSAError {
|
||||
ASN1DecodeErr(ASN1DecodeErr),
|
||||
InvalidParamSize
|
||||
}
|
||||
|
||||
impl From<ASN1DecodeErr> for DSAError {
|
||||
fn from(e: ASN1DecodeErr) -> DSAError {
|
||||
DSAError::ASN1DecodeErr(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DSAGenError {
|
||||
RngFailure(io::Error),
|
||||
InvalidSeedLength, InvalidPrimeLength, TooManyGenAttempts
|
||||
}
|
||||
|
||||
impl From<io::Error> for DSAGenError {
|
||||
fn from(e: io::Error) -> DSAGenError {
|
||||
DSAGenError::RngFailure(e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,585 +0,0 @@
|
||||
use cryptonum::{BarrettUCN,UCN};
|
||||
use digest::{FixedOutput,Input};
|
||||
use dsa::errors::DSAGenError;
|
||||
use dsa::parameters::{DSAParameterSize,n_bits,l_bits};
|
||||
use rand::Rng;
|
||||
use sha2::Sha256;
|
||||
use std::ops::{Add,Div,Rem,Sub};
|
||||
|
||||
#[derive(Debug,PartialEq)]
|
||||
pub struct DSAGenEvidence {
|
||||
pub first_seed: UCN,
|
||||
pub p_seed: UCN,
|
||||
pub q_seed: UCN,
|
||||
pub pgen_counter: usize,
|
||||
pub qgen_counter: usize
|
||||
}
|
||||
|
||||
fn get_domain_parameter_seed(ev: &DSAGenEvidence) -> Vec<u8> {
|
||||
let mut output = Vec::new();
|
||||
let fssize = (ev.first_seed.bits() + 7) / 8;
|
||||
output.append(&mut ev.first_seed.to_bytes(fssize));
|
||||
let psize = (ev.p_seed.bits() + 7) / 8;
|
||||
output.append(&mut ev.p_seed.to_bytes(psize));
|
||||
let qsize = (ev.q_seed.bits() + 7) / 8;
|
||||
output.append(&mut ev.q_seed.to_bytes(qsize));
|
||||
output
|
||||
}
|
||||
|
||||
pub fn generate_provable_primes<G: Rng>(rng: &mut G,
|
||||
firstseed: &UCN,
|
||||
ps: DSAParameterSize)
|
||||
-> Result<(UCN, UCN, DSAGenEvidence),DSAGenError>
|
||||
{
|
||||
let one: UCN = UCN::from(1u64);
|
||||
let two: UCN = UCN::from(2u64);
|
||||
let three: UCN = UCN::from(3u64);
|
||||
// See Page 38 of FIPS 186-4!
|
||||
let n = n_bits(ps);
|
||||
let l = l_bits(ps);
|
||||
// 1. Check that the (L, N) pair is in the list of acceptable (L, N) pairs
|
||||
// (see Section 4.2). If the pair is not in the list, return FAILURE.
|
||||
//
|
||||
// Done because sum types are cool.
|
||||
//
|
||||
// 2. Using N as the length and firstseed as the input_seed, use the random
|
||||
// prime generation routine in Appendix C.6 to obtain q, qseed and
|
||||
// qgen_counter. If FAILURE is returned, then return FAILURE.
|
||||
let (q, qseed, qgen_counter) = shawe_taylor(rng, n, &firstseed)?;
|
||||
// 3. Using ceiling(L / 2 + 1) as the length and qseed as the input_seed,
|
||||
// use the random prime generation routine in Appendix C.6 to obtain
|
||||
// p0, pseed, and pgen_counter. If FAILURE is returned, then return
|
||||
// FAILURE.
|
||||
//
|
||||
// NOTE: The ceiling isn't required. All of the values of L divide
|
||||
// evenly by 2, so it's just l / 2 + 1. I'm not sure why the
|
||||
// spec mentions it, frankly.
|
||||
let (p0, mut pseed, mut pgen_counter) = shawe_taylor(rng, l/2 + 1, &qseed)?;
|
||||
// 4. iterations = ceiling(L / outlen) - 1.
|
||||
let iterations = ceildiv(&l, &256) - 1;
|
||||
// 5. old_counter = pgen_counter.
|
||||
let old_counter = pgen_counter;
|
||||
// 6. x = 0.
|
||||
let mut x_bytes = Vec::new();
|
||||
// 7. For i = 0 to iterations fo
|
||||
// x + x + (Hash(pseed + i) * 2^(i * outlen).
|
||||
// NOTE: WE run this backwards, much like we do in shawe_taylor()
|
||||
let mut i: i64 = iterations as i64;
|
||||
while i >= 0 {
|
||||
let bigi = UCN::from(i as u64);
|
||||
let prime_i = &pseed + &bigi;
|
||||
let mut hash_i = hash(&prime_i, l);
|
||||
x_bytes.append(&mut hash_i);
|
||||
i -= 1;
|
||||
}
|
||||
let x = UCN::from_bytes(&x_bytes);
|
||||
// 8. pseed = pseed + iterations + 1.
|
||||
pseed = &pseed + UCN::from(iterations) + &one;
|
||||
// 9. x = 2^(L-1) + (x mod 2^(L-1));
|
||||
let twol1: UCN = &one << (l - 1);
|
||||
// 10. t = ceiling(x / (2 * q * p_0))
|
||||
let twoqp0 = &two * &q * &p0;
|
||||
let mut t = ceildiv(&x, &twoqp0);
|
||||
loop {
|
||||
// 11. If (2tqp_0 + 1) > 2^L, then t = ceiling(2^(L-1)/2qp0).
|
||||
let twotqp0p1 = (&t * &twoqp0) + &one;
|
||||
let twol = &one << l;
|
||||
if &twotqp0p1 > &twol {
|
||||
t = ceildiv(&twol1, &twoqp0);
|
||||
}
|
||||
// 12. p = 2tqp_0 + 1
|
||||
let p = twotqp0p1;
|
||||
// 13. pgen_counter = pgen_counter + 1
|
||||
pgen_counter = &pgen_counter + 1;
|
||||
// 14. a = 0
|
||||
let mut a_bytes = Vec::new();
|
||||
// 15. For i = 0 to iterations do
|
||||
// a = a + (Hash(pseed + i) * 2^(i*outlen).
|
||||
i = iterations as i64;
|
||||
while i >= 0 {
|
||||
let bigi = UCN::from(i as u64);
|
||||
let prime_i = &pseed + &bigi;
|
||||
let mut hash_i = hash(&prime_i, l);
|
||||
a_bytes.append(&mut hash_i);
|
||||
i -= 1;
|
||||
}
|
||||
let mut a = UCN::from_bytes(&a_bytes);
|
||||
// 16. pseed = pseed + iterations + 1.
|
||||
pseed = &pseed + UCN::from(iterations) + &one;
|
||||
// 17. a = 2 + (a mod (p - 3))
|
||||
let pm3 = &p - &three;
|
||||
let amodpm3 = &a % &pm3;
|
||||
a = &two + &amodpm3;
|
||||
// 18. z = a^(2tq) mod p.
|
||||
let twotq = &two * &t * &q;
|
||||
let z = a.modexp(&twotq, &p);
|
||||
// 19. If ((1 = GCD(z-1,p)) and (1 = z^p0 mod p)), then return SUCCESS
|
||||
// and the values of p, q, and (optionally) pseed, qseed, pgen_counter,
|
||||
// and qgen_counter.
|
||||
let zm1 = &z - &one;
|
||||
if (&one == &zm1.gcd(&p)) && (&one == &z.modexp(&p0, &p)) {
|
||||
let evidence = DSAGenEvidence {
|
||||
first_seed: firstseed.clone(),
|
||||
p_seed: pseed,
|
||||
q_seed: qseed,
|
||||
pgen_counter: pgen_counter,
|
||||
qgen_counter: qgen_counter
|
||||
};
|
||||
return Ok((p, q, evidence));
|
||||
}
|
||||
// 20. If (pgen_counter > (4L + old_counter)), then return FAILURE.
|
||||
if pgen_counter > ((4 * l) + old_counter) {
|
||||
return Err(DSAGenError::TooManyGenAttempts);
|
||||
}
|
||||
// 21. t = t + 1
|
||||
t = &t + &one;
|
||||
// 22. Go to step 11.
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_provable_primes<G: Rng>(rng: &mut G,
|
||||
p: &UCN, q: &UCN,
|
||||
ev: &DSAGenEvidence)
|
||||
-> bool
|
||||
{
|
||||
let one = UCN::from(1u64);
|
||||
// This is from Page 40 of 186-4, section A.1.2.2.
|
||||
// 1. L = len(p);
|
||||
let l = ((p.bits() + 255) / 256) * 256;
|
||||
// 2. N = len(q);
|
||||
let n = ((q.bits() + 15) / 16) * 16;
|
||||
// 3. Check that the (L, N) pair is in the list of acceptable (L, N) pairs.
|
||||
// If the pair is not in the list, then return failure.
|
||||
let params = match (l, n) {
|
||||
(1024, 160) => DSAParameterSize::L1024N160,
|
||||
(2048, 224) => DSAParameterSize::L2048N224,
|
||||
(2048, 256) => DSAParameterSize::L2048N256,
|
||||
(3072, 256) => DSAParameterSize::L3072N256,
|
||||
_ => return false
|
||||
};
|
||||
// 4. If (firstseed < 2^(n-1), then return FAILURE.
|
||||
let twon1 = &one << (n - 1);
|
||||
if &ev.first_seed < &twon1 {
|
||||
return false;
|
||||
}
|
||||
// 5. If (2^n <= q), then return FAILURE.
|
||||
let twon = &one << n;
|
||||
if &twon <= q {
|
||||
return false;
|
||||
}
|
||||
// 6. If (2^l <= p), then return FAILURE.
|
||||
let twol = &one << l;
|
||||
if &twol <= p {
|
||||
return false;
|
||||
}
|
||||
// 7. If ((p - 1) mod q /= 0), then return FAILURE.
|
||||
let pm1 = p - &one;
|
||||
if !pm1.rem(q).is_zero() {
|
||||
return false;
|
||||
}
|
||||
// 8. Using L, N and firstseed, perform the constructive prime generation
|
||||
// procedure in Appendix A.1.2.1.2 to obtain p_val, q_val, pseed_val,
|
||||
// qseed_val, pgen_counter_val, and qgen_counter_val. If FAILURE is
|
||||
// returned, or if (q_val ≠ q) or (qseed_val ≠ qseed) or
|
||||
// (qgen_counter_val ≠ qgen_counter) or (p_val ≠ p) or (pseed_val ≠
|
||||
// pseed) or (pgen_counter_val ≠ pgen_counter), then return FAILURE.
|
||||
match generate_provable_primes(rng, &ev.first_seed, params) {
|
||||
Err(_) => false,
|
||||
Ok((p_val, q_val, ev2)) => {
|
||||
// 9. Return SUCCESS
|
||||
(&q_val == q) && (&p_val == p) && (ev == &ev2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_verifiable_generator(p: &UCN, pu: &BarrettUCN,
|
||||
q: &UCN,
|
||||
ev: &DSAGenEvidence,
|
||||
index: u8)
|
||||
-> Result<UCN,DSAGenError>
|
||||
{
|
||||
// See FIPS 186-4, Section A.2.3: Verifiable Canonical Generatio of the
|
||||
// Generator g
|
||||
let one = UCN::from(1u64);
|
||||
let two = UCN::from(2u64);
|
||||
// 1. If (index is incorrect), then return INVALID.
|
||||
// NOTE: Can't happen, because types.
|
||||
// 2. N = len(q)
|
||||
let _n = q.bits();
|
||||
// 3. e = (p - 1)/q.
|
||||
let e = (p - &one) / q;
|
||||
// 4. count = 0.
|
||||
let mut count: u16 = 0;
|
||||
|
||||
loop {
|
||||
// 5. count = count + 1;
|
||||
count = count + 1;
|
||||
// 6. if (count = 0), then return INVALID.
|
||||
if count == 0 {
|
||||
return Err(DSAGenError::TooManyGenAttempts);
|
||||
}
|
||||
// 7. U = domain_parameter_seed || "ggen" || index || count
|
||||
// Comment: "ggen" is the bit string 0x6767656E.
|
||||
let mut u = get_domain_parameter_seed(&ev);
|
||||
u.push(0x67); u.push(0x67); u.push(0x65); u.push(0x6E);
|
||||
u.push(index);
|
||||
u.push((count >> 8) as u8); u.push((count & 0xFF) as u8);
|
||||
// 8. W = hash(U)
|
||||
let mut dgst = Sha256::default();
|
||||
dgst.process(&u);
|
||||
let w = UCN::from_bytes(dgst.fixed_result().as_slice());
|
||||
// 9. g = W^e mod p
|
||||
let g = w.fastmodexp(&e, &pu);
|
||||
// 10. if (g < 2), then go to step 5.
|
||||
if &g >= &two {
|
||||
// 11. Return VALID and the value of g.
|
||||
return Ok(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify_generator(p: &UCN, q: &UCN, ev: &DSAGenEvidence,
|
||||
index: u8, g: &UCN)
|
||||
-> bool
|
||||
{
|
||||
// FIPS 186.4, Section A.2.4!
|
||||
let one = UCN::from(1u64);
|
||||
let two = UCN::from(2u64);
|
||||
// 1. If (index is incorrect), then return INVALID.
|
||||
// NOTE: Not sure how this can be invalid.
|
||||
// 2. Verify that 2 <= g <= (p - 1). If not true, return INVALID.
|
||||
if g < &two {
|
||||
return false;
|
||||
}
|
||||
if g >= p {
|
||||
return false;
|
||||
}
|
||||
// 3. If (g^q /= 1 mod p), then return INVALID.
|
||||
if g.modexp(q, p) != one {
|
||||
return false;
|
||||
}
|
||||
// 4. N = len(q)
|
||||
// let n = ((q.bits() + 15) / 15) * 15;
|
||||
// 5. e = (p - 1) / q
|
||||
let e = (p - &one) / q;
|
||||
// 6. count = 0
|
||||
let mut count: u16 = 0;
|
||||
loop {
|
||||
// 7. count = count + 1
|
||||
count = count + 1;
|
||||
// 8. if (count == 0), then return INVALID
|
||||
if count == 0 {
|
||||
return false;
|
||||
}
|
||||
// 9. U = domain_parameter_seed || "ggen" || index || count.
|
||||
let mut u = get_domain_parameter_seed(&ev);
|
||||
u.push(0x67); u.push(0x67); u.push(0x65); u.push(0x6E);
|
||||
u.push(index);
|
||||
u.push((count >> 8) as u8); u.push((count & 0xFF) as u8);
|
||||
// 10. W = Hash(U)
|
||||
let mut dgst = Sha256::default();
|
||||
dgst.process(&u);
|
||||
let w = UCN::from_bytes(dgst.fixed_result().as_slice());
|
||||
// 11. computed_g = W^e mod p
|
||||
let computed_g = w.modexp(&e, &p);
|
||||
// 12. if (computed_g < 2), then go to step 7.
|
||||
if &computed_g < &two {
|
||||
continue;
|
||||
}
|
||||
// 13. if (computed_g == g), then return VALID, else return INVALID
|
||||
return &computed_g == g;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_input_seed<G: Rng>(rng: &mut G,
|
||||
size: DSAParameterSize,
|
||||
seedlen: usize)
|
||||
-> Result<UCN,DSAGenError>
|
||||
{
|
||||
let mut firstseed = UCN::from(0u64);
|
||||
let one = UCN::from(1u64);
|
||||
let n = n_bits(size);
|
||||
|
||||
// 3. If (seedlen < N), then return FAILURE
|
||||
if seedlen < n {
|
||||
return Err(DSAGenError::InvalidSeedLength)
|
||||
}
|
||||
// 4. While firstseed < 2^(n-1) ...
|
||||
let twonm1 = one << (n - 1);
|
||||
while &firstseed < &twonm1 {
|
||||
// Get an arbitrary sequence of seedlen bits as firstseed.
|
||||
let bytes: Vec<u8> = rng.gen_iter().take(seedlen / 8).collect();
|
||||
firstseed = UCN::from_bytes(&bytes);
|
||||
}
|
||||
// 5. Return SUCCESS and the value of firstseed
|
||||
Ok(firstseed)
|
||||
}
|
||||
|
||||
// Appendix C.6: Shawe-Taylor Random_Prime Routine. Also referenced in 186-4
|
||||
// as ST_Random_Prime, so when you see that in a bit, understand that it's a
|
||||
// recursive call.
|
||||
fn shawe_taylor<G: Rng>(rng: &mut G, length: usize, input_seed: &UCN)
|
||||
-> Result<(UCN,UCN,usize),DSAGenError>
|
||||
{
|
||||
// 1. If (length < 2), then return (FAILURE, 0, 0 {, 0}).
|
||||
if length < 2 {
|
||||
return Err(DSAGenError::InvalidPrimeLength);
|
||||
}
|
||||
// 2. If (length ≥ 33), then go to step 14.
|
||||
if length >= 33 {
|
||||
shawe_taylor_large(rng, length, input_seed)
|
||||
} else {
|
||||
shawe_taylor_small(length, input_seed)
|
||||
}
|
||||
}
|
||||
|
||||
fn shawe_taylor_small(length: usize, input_seed: &UCN)
|
||||
-> Result<(UCN,UCN,usize),DSAGenError>
|
||||
{
|
||||
let one = UCN::from(1u64);
|
||||
let two = UCN::from(2u64);
|
||||
// 3. prime_seed = input_seed.
|
||||
let mut prime_seed: UCN = input_seed.clone();
|
||||
// 4. prime_gen_counter = 0
|
||||
let mut prime_gen_counter = 0;
|
||||
loop {
|
||||
// 5. c = Hash(prime_seed) ⊕ Hash(prime_seed + 1).
|
||||
let cbs = xorvecs(hash(&prime_seed, length),
|
||||
hash(&(&prime_seed + &one), length));
|
||||
let mut c = UCN::from_bytes(&cbs);
|
||||
// 6. c = 2^(length – 1) + (c mod 2^(length – 1))
|
||||
let twolm1: UCN = &one << (length - 1);
|
||||
c = &twolm1 + (c % &twolm1);
|
||||
// 7. c = (2 ∗ floor(c / 2)) + 1.
|
||||
c = ((c >> 1) << 1) + &one;
|
||||
// 8. prime_gen_counter = prime_gen_counter + 1.
|
||||
prime_gen_counter = prime_gen_counter + 1;
|
||||
// 9. prime_seed = prime_seed + 2.
|
||||
prime_seed = prime_seed + &two;
|
||||
// 10. Perform a deterministic primality test on c. For example, since
|
||||
// c is small, its primality can be tested by trial division. See
|
||||
// Appendix C.7.
|
||||
let c_is_prime = prime_test(&c);
|
||||
// 11. If (c is a prime number), then
|
||||
if c_is_prime {
|
||||
// 11.1 prime = c.
|
||||
let prime = c;
|
||||
// 11.2 Return (SUCCESS, prime, prime_seed {, prime_gen_counter}).
|
||||
return Ok((prime, prime_seed.clone(), prime_gen_counter))
|
||||
}
|
||||
// 12. If (prime_gen_counter > (4 ∗ length)), then
|
||||
// return (FAILURE, 0, 0 {, 0}).
|
||||
if prime_gen_counter > (4 * length) {
|
||||
return Err(DSAGenError::TooManyGenAttempts);
|
||||
}
|
||||
// 13. Go to step 5.
|
||||
}
|
||||
}
|
||||
|
||||
fn shawe_taylor_large<G: Rng>(rng: &mut G, length: usize, input_seed: &UCN)
|
||||
-> Result<(UCN,UCN,usize),DSAGenError>
|
||||
{
|
||||
let one = UCN::from(1u64);
|
||||
let two = UCN::from(2u64);
|
||||
let three = UCN::from(3u64);
|
||||
// 14. (status, c0, prime_seed, prime_gen_counter) =
|
||||
// (ST_Random_Prime ((ceiling(length / 2) + 1), input_seed).
|
||||
let len2: usize = ceildiv(&length, &2);
|
||||
let (c0, mut prime_seed, mut prime_gen_counter) =
|
||||
shawe_taylor( rng, len2 + 1, input_seed )?;
|
||||
// 15. If FAILURE is returned, return (FAILURE, 0, 0 {, 0}).
|
||||
// 16. iterations = ceiling(length / outlen) – 1.
|
||||
let outlen = 256; // the size of the hash function output in bits
|
||||
let iterations = ceildiv(&length, &outlen) - 1;
|
||||
// 17. old_counter = prime_gen_counter.
|
||||
let old_counter = prime_gen_counter;
|
||||
// 18. x = 0.
|
||||
let mut x_bytes = Vec::new();
|
||||
// 19. For i = 0 to iterations do
|
||||
// x = x + (Hash(prime_seed + i) ∗ 2^(i * outlen)).
|
||||
//
|
||||
// We're going to actually run this backwards. What this computation
|
||||
// does is essentially built up a large vector of hashes, one per
|
||||
// iteration, shifting them bast each other via the 2^(i * outlen)
|
||||
// term. So we'll just do this directly.
|
||||
let mut i: i64 = iterations as i64;
|
||||
while i >= 0 {
|
||||
let bigi = UCN::from(i as u64);
|
||||
let prime_i = &prime_seed + &bigi;
|
||||
let mut hash_i = hash(&prime_i, length);
|
||||
x_bytes.append(&mut hash_i);
|
||||
i -= 1;
|
||||
}
|
||||
let mut x = UCN::from_bytes(&x_bytes);
|
||||
// 20. prime_seed = prime_seed + iterations + 1.
|
||||
prime_seed = &prime_seed + UCN::from(iterations) + &one;
|
||||
// 21. x = 2^(length – 1) + (x mod 2^(length – 1)).
|
||||
let twolm1 = &one << (length - 1);
|
||||
x = &twolm1 + (&x % &twolm1);
|
||||
// 22. t = ceiling(x / (2c0)).
|
||||
let twoc0 = &two * &c0;
|
||||
let mut t: UCN = ceildiv(&x, &twoc0);
|
||||
loop {
|
||||
// 23. If (2tc0 + 1 > 2^length), then
|
||||
// t = ceiling(2^(length – 1) / (2c0)).
|
||||
let twotc0 = &t * &twoc0;
|
||||
if (&twotc0 + &one) > (&one << length) {
|
||||
t = ceildiv(&twolm1, &twoc0);
|
||||
}
|
||||
// 24. c = 2tc0 + 1.
|
||||
let c = &twotc0 + &one;
|
||||
|
||||
// 25. prime_gen_counter = prime_gen_counter + 1.
|
||||
prime_gen_counter = prime_gen_counter + 1;
|
||||
// 26. a = 0.
|
||||
let mut a_bytes = Vec::new();
|
||||
// 27. For i = 0 to iterations do
|
||||
// a = a + (Hash(prime_seed + i) ∗ 2 i * outlen).
|
||||
//
|
||||
// As with the last time we did this, we're going to do this more
|
||||
// constructively
|
||||
i = iterations as i64;
|
||||
while i >= 0 {
|
||||
let bigi = UCN::from(i as u64);
|
||||
let prime_i = &prime_seed + &bigi;
|
||||
let mut hash_i = hash(&prime_i, length);
|
||||
a_bytes.append(&mut hash_i);
|
||||
i -= 1;
|
||||
}
|
||||
let mut a = UCN::from_bytes(&a_bytes);
|
||||
// 28. prime_seed = prime_seed + iterations + 1.
|
||||
prime_seed = &prime_seed + UCN::from(iterations) + &one;
|
||||
// 29. a = 2 + (a mod (c – 3)).
|
||||
a = &two + (a % (&c - &three));
|
||||
// 30. z = a^2t mod c.
|
||||
let z: UCN = a.modexp(&(&two * &t), &c);
|
||||
// 31. If ((1 = GCD(z – 1, c)) and (1 = z^c_0 mod c)), then
|
||||
let gcd_ok = &one == &c.gcd(&(&z - &one));
|
||||
let modexp_ok = &one == &z.modexp(&c0, &c);
|
||||
if gcd_ok && modexp_ok {
|
||||
// 31.1 prime = c.
|
||||
let prime = c;
|
||||
// 31.2 Return (SUCCESS, prime, prime_seed {, prime_gen_counter}).
|
||||
return Ok((prime, prime_seed, prime_gen_counter));
|
||||
}
|
||||
// 32. If (prime_gen_counter ≥ ((4 ∗ length) + old_counter)), then
|
||||
// return (FAILURE, 0, 0 {, 0}).
|
||||
let limit = (4 * length) + old_counter;
|
||||
if prime_gen_counter >= limit {
|
||||
return Err(DSAGenError::TooManyGenAttempts)
|
||||
}
|
||||
// 33. t = t + 1.
|
||||
t = t + &one;
|
||||
// 34. Go to step 23.
|
||||
}
|
||||
}
|
||||
|
||||
fn ceildiv<T>(a: &T, b: &T) -> T
|
||||
where T: Add<Output=T>,
|
||||
T: Sub<Output=T>,
|
||||
T: Div<Output=T>,
|
||||
T: From<usize>,
|
||||
T: Clone
|
||||
{
|
||||
let aclone: T = a.clone();
|
||||
let bclone: T = b.clone();
|
||||
let one: T = T::from(1 as usize);
|
||||
let x: T = (aclone + bclone.clone()) - one;
|
||||
let res = x / bclone;
|
||||
res
|
||||
}
|
||||
|
||||
fn prime_test(x: &UCN) -> bool {
|
||||
let two = UCN::from(2 as u64);
|
||||
let three = UCN::from(3 as u64);
|
||||
let five = UCN::from(5 as u64);
|
||||
|
||||
if x.is_even() {
|
||||
if x == &two {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if x.is_multiple_of(&three) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if x.is_multiple_of(&five) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut divisor = UCN::from(7 as u32);
|
||||
let sqrtx = isqrt(&x);
|
||||
while &divisor < &sqrtx {
|
||||
if x.is_multiple_of(&divisor) {
|
||||
return false;
|
||||
}
|
||||
divisor = next_divisor(divisor);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn isqrt(x: &UCN) -> UCN {
|
||||
let mut num = x.clone();
|
||||
let mut res = UCN::from(0u64);
|
||||
let one = UCN::from(1u64);
|
||||
let mut bit = one << num.bits();
|
||||
|
||||
while &bit > &num {
|
||||
bit >>= 2;
|
||||
}
|
||||
|
||||
while !bit.is_zero() {
|
||||
if num >= (&res + &bit) {
|
||||
num = &num - (&res + &bit);
|
||||
res = (&res >> 1) + &bit;
|
||||
} else {
|
||||
res >>= 1;
|
||||
}
|
||||
bit >>= 2;
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn next_divisor(input: UCN) -> UCN {
|
||||
let two = UCN::from(2 as u64);
|
||||
let three = UCN::from(3 as u64);
|
||||
let five = UCN::from(5 as u64);
|
||||
let mut x = input;
|
||||
|
||||
loop {
|
||||
x = &x + &two;
|
||||
|
||||
if x.is_multiple_of(&three) {
|
||||
continue;
|
||||
}
|
||||
if x.is_multiple_of(&five) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
fn hash(x: &UCN, len: usize) -> Vec<u8> {
|
||||
let bytelen = len / 8;
|
||||
let base = x.to_bytes(bytelen);
|
||||
let mut dgst = Sha256::default();
|
||||
dgst.process(&base);
|
||||
dgst.fixed_result().as_slice().to_vec()
|
||||
}
|
||||
|
||||
fn xorvecs(a: Vec<u8>, b: Vec<u8>) -> Vec<u8> {
|
||||
assert!(a.len() == b.len());
|
||||
let mut c = Vec::with_capacity(a.len());
|
||||
|
||||
for (a,b) in a.iter().zip(b.iter()) {
|
||||
c.push(a ^ b);
|
||||
}
|
||||
c
|
||||
}
|
||||
|
||||
|
||||
@@ -1,646 +0,0 @@
|
||||
use cryptonum::UCN;
|
||||
use digest::{FixedOutput,Input};
|
||||
use dsa::generation::*;
|
||||
use dsa::rfc6979::*;
|
||||
use dsa::parameters::*;
|
||||
use dsa::private::DSAPrivate;
|
||||
use dsa::public::DSAPublic;
|
||||
use rand::{OsRng,Rng};
|
||||
use sha1::Sha1;
|
||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||
use simple_asn1::{der_decode,der_encode};
|
||||
use testing::run_test;
|
||||
|
||||
const NUM_TESTS: u32 = 2;
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn pqg_generation_checks() {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let params = DSAParameterSize::L1024N160;
|
||||
|
||||
for _ in 0..NUM_TESTS {
|
||||
let seed = get_input_seed(&mut rng,params,n_bits(params)).unwrap();
|
||||
let (p, q, ev) =
|
||||
generate_provable_primes(&mut rng, &seed, params).unwrap();
|
||||
assert!(validate_provable_primes(&mut rng, &p, &q, &ev));
|
||||
let index = rng.gen::<u8>();
|
||||
let pu = p.barrett_u();
|
||||
let g = generate_verifiable_generator(&p, &pu, &q, &ev, index).unwrap();
|
||||
assert!(verify_generator(&p, &q, &ev, index, &g));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dsa_verification_tests()
|
||||
{
|
||||
run_test("tests/dsa/signature.test", 9, |case| {
|
||||
let (neg0, pbytes) = case.get("p").unwrap();
|
||||
let (neg1, gbytes) = case.get("g").unwrap();
|
||||
let (neg2, qbytes) = case.get("q").unwrap();
|
||||
let (neg4, ybytes) = case.get("y").unwrap();
|
||||
let (neg5, hbytes) = case.get("h").unwrap();
|
||||
let (neg6, msg) = case.get("m").unwrap();
|
||||
let (neg7, rbytes) = case.get("r").unwrap();
|
||||
let (neg8, sbytes) = case.get("s").unwrap();
|
||||
|
||||
assert!(!neg0 & !neg1 & !neg2 & !neg4 &
|
||||
!neg5 & !neg6 & !neg7 & !neg8);
|
||||
|
||||
let p = UCN::from_bytes(pbytes);
|
||||
let g = UCN::from_bytes(gbytes);
|
||||
let q = UCN::from_bytes(qbytes);
|
||||
let params = DSAParameters::new(p, g, q).unwrap();
|
||||
let y = UCN::from_bytes(ybytes);
|
||||
let public = DSAPublic::new(¶ms, y);
|
||||
let r = UCN::from_bytes(rbytes);
|
||||
let s = UCN::from_bytes(sbytes);
|
||||
let sig = DSASignature{ r: r, s: s };
|
||||
|
||||
match usize::from(UCN::from_bytes(hbytes)) {
|
||||
0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
|
||||
0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
|
||||
0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
|
||||
0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
|
||||
0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
|
||||
v => panic!("Bad hash size {}!", v)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn dsa_signing_tests()
|
||||
{
|
||||
run_test("tests/dsa/signature.test", 9, |case| {
|
||||
let (neg0, pbytes) = case.get("p").unwrap();
|
||||
let (neg1, gbytes) = case.get("g").unwrap();
|
||||
let (neg2, qbytes) = case.get("q").unwrap();
|
||||
let (neg3, xbytes) = case.get("x").unwrap();
|
||||
let (neg4, ybytes) = case.get("y").unwrap();
|
||||
let (neg5, hbytes) = case.get("h").unwrap();
|
||||
let (neg6, msg) = case.get("m").unwrap();
|
||||
|
||||
|
||||
assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
|
||||
|
||||
let p = UCN::from_bytes(pbytes);
|
||||
let g = UCN::from_bytes(gbytes);
|
||||
let q = UCN::from_bytes(qbytes);
|
||||
let params = DSAParameters::new(p, g, q).unwrap();
|
||||
let y = UCN::from_bytes(ybytes);
|
||||
let public = DSAPublic::new(¶ms, y);
|
||||
let x = UCN::from_bytes(xbytes);
|
||||
let private = DSAPrivate::new(¶ms, x);
|
||||
let hash_size = usize::from(UCN::from_bytes(hbytes));
|
||||
|
||||
let sig = match hash_size {
|
||||
0x1 => private.sign::<Sha1>(msg),
|
||||
0x224 => private.sign::<Sha224>(msg),
|
||||
0x256 => private.sign::<Sha256>(msg),
|
||||
0x384 => private.sign::<Sha384>(msg),
|
||||
0x512 => private.sign::<Sha512>(msg),
|
||||
v => panic!("Bad hash size {}!", v)
|
||||
};
|
||||
|
||||
match usize::from(UCN::from_bytes(hbytes)) {
|
||||
0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
|
||||
0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
|
||||
0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
|
||||
0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
|
||||
0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
|
||||
v => panic!("Bad hash size {}!", v)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! run_rfc6979_test {
|
||||
($hash: ty, $val: ident, $public: ident, $private: ident,
|
||||
k $k: expr,
|
||||
r $r: expr,
|
||||
s $s: expr) => ({
|
||||
let mut digest = <$hash>::default();
|
||||
digest.process(&$val);
|
||||
let h1 = digest.fixed_result().as_slice().to_vec();
|
||||
let rbytes = $r;
|
||||
let sbytes = $s;
|
||||
let r = UCN::from_bytes(&rbytes);
|
||||
let s = UCN::from_bytes(&sbytes);
|
||||
let mut iter = KIterator::<$hash>::new(&h1,
|
||||
n_bits($public.params.size),
|
||||
&$public.params.q,
|
||||
&$private.x);
|
||||
let next = iter.next().unwrap();
|
||||
let size = (next.bits() + 7) / 8;
|
||||
let k1 = next.to_bytes(size);
|
||||
assert_eq!($k, k1);
|
||||
let sig = $private.sign::<$hash>(&$val);
|
||||
assert_eq!(sig.r, r);
|
||||
assert_eq!(sig.s, s);
|
||||
assert!($public.verify::<$hash>(&$val, &sig));
|
||||
let blocks = der_encode(&sig).unwrap();
|
||||
let sig2 = der_decode(&blocks).unwrap();
|
||||
assert_eq!(sig, sig2);
|
||||
})
|
||||
}
|
||||
|
||||
// these appendix_* tests are out of RFC6979
|
||||
#[test]
|
||||
fn appendix_a21() {
|
||||
let pbytes = vec![0x86, 0xF5, 0xCA, 0x03, 0xDC, 0xFE, 0xB2, 0x25,
|
||||
0x06, 0x3F, 0xF8, 0x30, 0xA0, 0xC7, 0x69, 0xB9,
|
||||
0xDD, 0x9D, 0x61, 0x53, 0xAD, 0x91, 0xD7, 0xCE,
|
||||
0x27, 0xF7, 0x87, 0xC4, 0x32, 0x78, 0xB4, 0x47,
|
||||
0xE6, 0x53, 0x3B, 0x86, 0xB1, 0x8B, 0xED, 0x6E,
|
||||
0x8A, 0x48, 0xB7, 0x84, 0xA1, 0x4C, 0x25, 0x2C,
|
||||
0x5B, 0xE0, 0xDB, 0xF6, 0x0B, 0x86, 0xD6, 0x38,
|
||||
0x5B, 0xD2, 0xF1, 0x2F, 0xB7, 0x63, 0xED, 0x88,
|
||||
0x73, 0xAB, 0xFD, 0x3F, 0x5B, 0xA2, 0xE0, 0xA8,
|
||||
0xC0, 0xA5, 0x90, 0x82, 0xEA, 0xC0, 0x56, 0x93,
|
||||
0x5E, 0x52, 0x9D, 0xAF, 0x7C, 0x61, 0x04, 0x67,
|
||||
0x89, 0x9C, 0x77, 0xAD, 0xED, 0xFC, 0x84, 0x6C,
|
||||
0x88, 0x18, 0x70, 0xB7, 0xB1, 0x9B, 0x2B, 0x58,
|
||||
0xF9, 0xBE, 0x05, 0x21, 0xA1, 0x70, 0x02, 0xE3,
|
||||
0xBD, 0xD6, 0xB8, 0x66, 0x85, 0xEE, 0x90, 0xB3,
|
||||
0xD9, 0xA1, 0xB0, 0x2B, 0x78, 0x2B, 0x17, 0x79];
|
||||
let qbytes = vec![0x99, 0x6F, 0x96, 0x7F, 0x6C, 0x8E, 0x38, 0x8D,
|
||||
0x9E, 0x28, 0xD0, 0x1E, 0x20, 0x5F, 0xBA, 0x95,
|
||||
0x7A, 0x56, 0x98, 0xB1];
|
||||
let gbytes = vec![0x07, 0xB0, 0xF9, 0x25, 0x46, 0x15, 0x0B, 0x62,
|
||||
0x51, 0x4B, 0xB7, 0x71, 0xE2, 0xA0, 0xC0, 0xCE,
|
||||
0x38, 0x7F, 0x03, 0xBD, 0xA6, 0xC5, 0x6B, 0x50,
|
||||
0x52, 0x09, 0xFF, 0x25, 0xFD, 0x3C, 0x13, 0x3D,
|
||||
0x89, 0xBB, 0xCD, 0x97, 0xE9, 0x04, 0xE0, 0x91,
|
||||
0x14, 0xD9, 0xA7, 0xDE, 0xFD, 0xEA, 0xDF, 0xC9,
|
||||
0x07, 0x8E, 0xA5, 0x44, 0xD2, 0xE4, 0x01, 0xAE,
|
||||
0xEC, 0xC4, 0x0B, 0xB9, 0xFB, 0xBF, 0x78, 0xFD,
|
||||
0x87, 0x99, 0x5A, 0x10, 0xA1, 0xC2, 0x7C, 0xB7,
|
||||
0x78, 0x9B, 0x59, 0x4B, 0xA7, 0xEF, 0xB5, 0xC4,
|
||||
0x32, 0x6A, 0x9F, 0xE5, 0x9A, 0x07, 0x0E, 0x13,
|
||||
0x6D, 0xB7, 0x71, 0x75, 0x46, 0x4A, 0xDC, 0xA4,
|
||||
0x17, 0xBE, 0x5D, 0xCE, 0x2F, 0x40, 0xD1, 0x0A,
|
||||
0x46, 0xA3, 0xA3, 0x94, 0x3F, 0x26, 0xAB, 0x7F,
|
||||
0xD9, 0xC0, 0x39, 0x8F, 0xF8, 0xC7, 0x6E, 0xE0,
|
||||
0xA5, 0x68, 0x26, 0xA8, 0xA8, 0x8F, 0x1D, 0xBD];
|
||||
let xbytes = vec![0x41, 0x16, 0x02, 0xCB, 0x19, 0xA6, 0xCC, 0xC3,
|
||||
0x44, 0x94, 0xD7, 0x9D, 0x98, 0xEF, 0x1E, 0x7E,
|
||||
0xD5, 0xAF, 0x25, 0xF7];
|
||||
let ybytes = vec![0x5D, 0xF5, 0xE0, 0x1D, 0xED, 0x31, 0xD0, 0x29,
|
||||
0x7E, 0x27, 0x4E, 0x16, 0x91, 0xC1, 0x92, 0xFE,
|
||||
0x58, 0x68, 0xFE, 0xF9, 0xE1, 0x9A, 0x84, 0x77,
|
||||
0x64, 0x54, 0xB1, 0x00, 0xCF, 0x16, 0xF6, 0x53,
|
||||
0x92, 0x19, 0x5A, 0x38, 0xB9, 0x05, 0x23, 0xE2,
|
||||
0x54, 0x2E, 0xE6, 0x18, 0x71, 0xC0, 0x44, 0x0C,
|
||||
0xB8, 0x7C, 0x32, 0x2F, 0xC4, 0xB4, 0xD2, 0xEC,
|
||||
0x5E, 0x1E, 0x7E, 0xC7, 0x66, 0xE1, 0xBE, 0x8D,
|
||||
0x4C, 0xE9, 0x35, 0x43, 0x7D, 0xC1, 0x1C, 0x3C,
|
||||
0x8F, 0xD4, 0x26, 0x33, 0x89, 0x33, 0xEB, 0xFE,
|
||||
0x73, 0x9C, 0xB3, 0x46, 0x5F, 0x4D, 0x36, 0x68,
|
||||
0xC5, 0xE4, 0x73, 0x50, 0x82, 0x53, 0xB1, 0xE6,
|
||||
0x82, 0xF6, 0x5C, 0xBD, 0xC4, 0xFA, 0xE9, 0x3C,
|
||||
0x2E, 0xA2, 0x12, 0x39, 0x0E, 0x54, 0x90, 0x5A,
|
||||
0x86, 0xE2, 0x22, 0x31, 0x70, 0xB4, 0x4E, 0xAA,
|
||||
0x7D, 0xA5, 0xDD, 0x9F, 0xFC, 0xFB, 0x7F, 0x3B];
|
||||
//
|
||||
let p = UCN::from_bytes(&pbytes);
|
||||
let q = UCN::from_bytes(&qbytes);
|
||||
let g = UCN::from_bytes(&gbytes);
|
||||
let params = DSAParameters::new(p, g, q).unwrap();
|
||||
let x = UCN::from_bytes(&xbytes);
|
||||
let y = UCN::from_bytes(&ybytes);
|
||||
let private = DSAPrivate::new(¶ms, x);
|
||||
let public = DSAPublic::new(¶ms, y);
|
||||
//
|
||||
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
||||
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
||||
// With SHA-1, message = "sample":
|
||||
// k = 7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B
|
||||
// r = 2E1A0C2562B2912CAAF89186FB0F42001585DA55
|
||||
// s = 29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5
|
||||
run_rfc6979_test!(Sha1, sample, public, private,
|
||||
k vec![0x7B, 0xDB, 0x6B, 0x0F, 0xF7, 0x56, 0xE1, 0xBB,
|
||||
0x5D, 0x53, 0x58, 0x3E, 0xF9, 0x79, 0x08, 0x2F,
|
||||
0x9A, 0xD5, 0xBD, 0x5B],
|
||||
r vec![0x2E, 0x1A, 0x0C, 0x25, 0x62, 0xB2, 0x91, 0x2C,
|
||||
0xAA, 0xF8, 0x91, 0x86, 0xFB, 0x0F, 0x42, 0x00,
|
||||
0x15, 0x85, 0xDA, 0x55],
|
||||
s vec![0x29, 0xEF, 0xB6, 0xB0, 0xAF, 0xF2, 0xD7, 0xA6,
|
||||
0x8E, 0xB7, 0x0C, 0xA3, 0x13, 0x02, 0x22, 0x53,
|
||||
0xB9, 0xA8, 0x8D, 0xF5]);
|
||||
// With SHA-224, message = "sample":
|
||||
// k = 562097C06782D60C3037BA7BE104774344687649
|
||||
// r = 4BC3B686AEA70145856814A6F1BB53346F02101E
|
||||
// s = 410697B92295D994D21EDD2F4ADA85566F6F94C1
|
||||
run_rfc6979_test!(Sha224, sample, public, private,
|
||||
k vec![0x56, 0x20, 0x97, 0xC0, 0x67, 0x82, 0xD6, 0x0C,
|
||||
0x30, 0x37, 0xBA, 0x7B, 0xE1, 0x04, 0x77, 0x43,
|
||||
0x44, 0x68, 0x76, 0x49],
|
||||
r vec![0x4B, 0xC3, 0xB6, 0x86, 0xAE, 0xA7, 0x01, 0x45,
|
||||
0x85, 0x68, 0x14, 0xA6, 0xF1, 0xBB, 0x53, 0x34,
|
||||
0x6F, 0x02, 0x10, 0x1E],
|
||||
s vec![0x41, 0x06, 0x97, 0xB9, 0x22, 0x95, 0xD9, 0x94,
|
||||
0xD2, 0x1E, 0xDD, 0x2F, 0x4A, 0xDA, 0x85, 0x56,
|
||||
0x6F, 0x6F, 0x94, 0xC1]);
|
||||
// With SHA-256, message = "sample":
|
||||
// k = 519BA0546D0C39202A7D34D7DFA5E760B318BCFB
|
||||
// r = 81F2F5850BE5BC123C43F71A3033E9384611C545
|
||||
// s = 4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89
|
||||
run_rfc6979_test!(Sha256, sample, public, private,
|
||||
k vec![0x51, 0x9B, 0xA0, 0x54, 0x6D, 0x0C, 0x39, 0x20,
|
||||
0x2A, 0x7D, 0x34, 0xD7, 0xDF, 0xA5, 0xE7, 0x60,
|
||||
0xB3, 0x18, 0xBC, 0xFB],
|
||||
r vec![0x81, 0xF2, 0xF5, 0x85, 0x0B, 0xE5, 0xBC, 0x12,
|
||||
0x3C, 0x43, 0xF7, 0x1A, 0x30, 0x33, 0xE9, 0x38,
|
||||
0x46, 0x11, 0xC5, 0x45],
|
||||
s vec![0x4C, 0xDD, 0x91, 0x4B, 0x65, 0xEB, 0x6C, 0x66,
|
||||
0xA8, 0xAA, 0xAD, 0x27, 0x29, 0x9B, 0xEE, 0x6B,
|
||||
0x03, 0x5F, 0x5E, 0x89]);
|
||||
// With SHA-384, message = "sample":
|
||||
// k = 95897CD7BBB944AA932DBC579C1C09EB6FCFC595
|
||||
// r = 07F2108557EE0E3921BC1774F1CA9B410B4CE65A
|
||||
// s = 54DF70456C86FAC10FAB47C1949AB83F2C6F7595
|
||||
run_rfc6979_test!(Sha384, sample, public, private,
|
||||
k vec![0x95, 0x89, 0x7C, 0xD7, 0xBB, 0xB9, 0x44, 0xAA,
|
||||
0x93, 0x2D, 0xBC, 0x57, 0x9C, 0x1C, 0x09, 0xEB,
|
||||
0x6F, 0xCF, 0xC5, 0x95],
|
||||
r vec![0x07, 0xF2, 0x10, 0x85, 0x57, 0xEE, 0x0E, 0x39,
|
||||
0x21, 0xBC, 0x17, 0x74, 0xF1, 0xCA, 0x9B, 0x41,
|
||||
0x0B, 0x4C, 0xE6, 0x5A],
|
||||
s vec![0x54, 0xDF, 0x70, 0x45, 0x6C, 0x86, 0xFA, 0xC1,
|
||||
0x0F, 0xAB, 0x47, 0xC1, 0x94, 0x9A, 0xB8, 0x3F,
|
||||
0x2C, 0x6F, 0x75, 0x95]);
|
||||
// With SHA-512, message = "sample":
|
||||
// k = 09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B
|
||||
// r = 16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B
|
||||
// s = 02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C
|
||||
run_rfc6979_test!(Sha512, sample, public, private,
|
||||
k vec![0x09, 0xEC, 0xE7, 0xCA, 0x27, 0xD0, 0xF5, 0xA4,
|
||||
0xDD, 0x4E, 0x55, 0x6C, 0x9D, 0xF1, 0xD2, 0x1D,
|
||||
0x28, 0x10, 0x4F, 0x8B],
|
||||
r vec![0x16, 0xC3, 0x49, 0x1F, 0x9B, 0x8C, 0x3F, 0xBB,
|
||||
0xDD, 0x5E, 0x7A, 0x7B, 0x66, 0x70, 0x57, 0xF0,
|
||||
0xD8, 0xEE, 0x8E, 0x1B],
|
||||
s vec![0x02, 0xC3, 0x6A, 0x12, 0x7A, 0x7B, 0x89, 0xED,
|
||||
0xBB, 0x72, 0xE4, 0xFF, 0xBC, 0x71, 0xDA, 0xBC,
|
||||
0x7D, 0x4F, 0xC6, 0x9C]);
|
||||
// With SHA-1, message = "test":
|
||||
// k = 5C842DF4F9E344EE09F056838B42C7A17F4A6433
|
||||
// r = 42AB2052FD43E123F0607F115052A67DCD9C5C77
|
||||
// s = 183916B0230D45B9931491D4C6B0BD2FB4AAF088
|
||||
run_rfc6979_test!(Sha1, test, public, private,
|
||||
k vec![0x5C, 0x84, 0x2D, 0xF4, 0xF9, 0xE3, 0x44, 0xEE,
|
||||
0x09, 0xF0, 0x56, 0x83, 0x8B, 0x42, 0xC7, 0xA1,
|
||||
0x7F, 0x4A, 0x64, 0x33],
|
||||
r vec![0x42, 0xAB, 0x20, 0x52, 0xFD, 0x43, 0xE1, 0x23,
|
||||
0xF0, 0x60, 0x7F, 0x11, 0x50, 0x52, 0xA6, 0x7D,
|
||||
0xCD, 0x9C, 0x5C, 0x77],
|
||||
s vec![0x18, 0x39, 0x16, 0xB0, 0x23, 0x0D, 0x45, 0xB9,
|
||||
0x93, 0x14, 0x91, 0xD4, 0xC6, 0xB0, 0xBD, 0x2F,
|
||||
0xB4, 0xAA, 0xF0, 0x88]);
|
||||
// With SHA-224, message = "test":
|
||||
// k = 4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297
|
||||
// r = 6868E9964E36C1689F6037F91F28D5F2C30610F2
|
||||
// s = 49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F
|
||||
run_rfc6979_test!(Sha224, test, public, private,
|
||||
k vec![0x45, 0x98, 0xB8, 0xEF, 0xC1, 0xA5, 0x3B, 0xC8,
|
||||
0xAE, 0xCD, 0x58, 0xD1, 0xAB, 0xBB, 0x0C, 0x0C,
|
||||
0x71, 0xE6, 0x72, 0x97],
|
||||
r vec![0x68, 0x68, 0xE9, 0x96, 0x4E, 0x36, 0xC1, 0x68,
|
||||
0x9F, 0x60, 0x37, 0xF9, 0x1F, 0x28, 0xD5, 0xF2,
|
||||
0xC3, 0x06, 0x10, 0xF2],
|
||||
s vec![0x49, 0xCE, 0xC3, 0xAC, 0xDC, 0x83, 0x01, 0x8C,
|
||||
0x5B, 0xD2, 0x67, 0x4E, 0xCA, 0xAD, 0x35, 0xB8,
|
||||
0xCD, 0x22, 0x94, 0x0F]);
|
||||
// With SHA-256, message = "test":
|
||||
// k = 5A67592E8128E03A417B0484410FB72C0B630E1A
|
||||
// r = 22518C127299B0F6FDC9872B282B9E70D0790812
|
||||
// s = 6837EC18F150D55DE95B5E29BE7AF5D01E4FE160
|
||||
run_rfc6979_test!(Sha256, test, public, private,
|
||||
k vec![0x5A, 0x67, 0x59, 0x2E, 0x81, 0x28, 0xE0, 0x3A,
|
||||
0x41, 0x7B, 0x04, 0x84, 0x41, 0x0F, 0xB7, 0x2C,
|
||||
0x0B, 0x63, 0x0E, 0x1A],
|
||||
r vec![0x22, 0x51, 0x8C, 0x12, 0x72, 0x99, 0xB0, 0xF6,
|
||||
0xFD, 0xC9, 0x87, 0x2B, 0x28, 0x2B, 0x9E, 0x70,
|
||||
0xD0, 0x79, 0x08, 0x12],
|
||||
s vec![0x68, 0x37, 0xEC, 0x18, 0xF1, 0x50, 0xD5, 0x5D,
|
||||
0xE9, 0x5B, 0x5E, 0x29, 0xBE, 0x7A, 0xF5, 0xD0,
|
||||
0x1E, 0x4F, 0xE1, 0x60]);
|
||||
// With SHA-384, message = "test":
|
||||
// k = 220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89
|
||||
// r = 854CF929B58D73C3CBFDC421E8D5430CD6DB5E66
|
||||
// s = 91D0E0F53E22F898D158380676A871A157CDA622
|
||||
run_rfc6979_test!(Sha384, test, public, private,
|
||||
k vec![0x22, 0x01, 0x56, 0xB7, 0x61, 0xF6, 0xCA, 0x5E,
|
||||
0x6C, 0x9F, 0x1B, 0x9C, 0xF9, 0xC2, 0x4B, 0xE2,
|
||||
0x5F, 0x98, 0xCD, 0x89],
|
||||
r vec![0x85, 0x4C, 0xF9, 0x29, 0xB5, 0x8D, 0x73, 0xC3,
|
||||
0xCB, 0xFD, 0xC4, 0x21, 0xE8, 0xD5, 0x43, 0x0C,
|
||||
0xD6, 0xDB, 0x5E, 0x66],
|
||||
s vec![0x91, 0xD0, 0xE0, 0xF5, 0x3E, 0x22, 0xF8, 0x98,
|
||||
0xD1, 0x58, 0x38, 0x06, 0x76, 0xA8, 0x71, 0xA1,
|
||||
0x57, 0xCD, 0xA6, 0x22]);
|
||||
// With SHA-512, message = "test":
|
||||
// k = 65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C
|
||||
// r = 8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0
|
||||
// s = 7C670C7AD72B6C050C109E1790008097125433E8
|
||||
run_rfc6979_test!(Sha512, test, public, private,
|
||||
k vec![0x65, 0xD2, 0xC2, 0xEE, 0xB1, 0x75, 0xE3, 0x70,
|
||||
0xF2, 0x8C, 0x75, 0xBF, 0xCD, 0xC0, 0x28, 0xD2,
|
||||
0x2C, 0x7D, 0xBE, 0x9C],
|
||||
r vec![0x8E, 0xA4, 0x7E, 0x47, 0x5B, 0xA8, 0xAC, 0x6F,
|
||||
0x2D, 0x82, 0x1D, 0xA3, 0xBD, 0x21, 0x2D, 0x11,
|
||||
0xA3, 0xDE, 0xB9, 0xA0],
|
||||
s vec![0x7C, 0x67, 0x0C, 0x7A, 0xD7, 0x2B, 0x6C, 0x05,
|
||||
0x0C, 0x10, 0x9E, 0x17, 0x90, 0x00, 0x80, 0x97,
|
||||
0x12, 0x54, 0x33, 0xE8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn appendix_a22() {
|
||||
let pbytes = vec![0x9D,0xB6,0xFB,0x59,0x51,0xB6,0x6B,0xB6,
|
||||
0xFE,0x1E,0x14,0x0F,0x1D,0x2C,0xE5,0x50,
|
||||
0x23,0x74,0x16,0x1F,0xD6,0x53,0x8D,0xF1,
|
||||
0x64,0x82,0x18,0x64,0x2F,0x0B,0x5C,0x48,
|
||||
0xC8,0xF7,0xA4,0x1A,0xAD,0xFA,0x18,0x73,
|
||||
0x24,0xB8,0x76,0x74,0xFA,0x18,0x22,0xB0,
|
||||
0x0F,0x1E,0xCF,0x81,0x36,0x94,0x3D,0x7C,
|
||||
0x55,0x75,0x72,0x64,0xE5,0xA1,0xA4,0x4F,
|
||||
0xFE,0x01,0x2E,0x99,0x36,0xE0,0x0C,0x1D,
|
||||
0x3E,0x93,0x10,0xB0,0x1C,0x7D,0x17,0x98,
|
||||
0x05,0xD3,0x05,0x8B,0x2A,0x9F,0x4B,0xB6,
|
||||
0xF9,0x71,0x6B,0xFE,0x61,0x17,0xC6,0xB5,
|
||||
0xB3,0xCC,0x4D,0x9B,0xE3,0x41,0x10,0x4A,
|
||||
0xD4,0xA8,0x0A,0xD6,0xC9,0x4E,0x00,0x5F,
|
||||
0x4B,0x99,0x3E,0x14,0xF0,0x91,0xEB,0x51,
|
||||
0x74,0x3B,0xF3,0x30,0x50,0xC3,0x8D,0xE2,
|
||||
0x35,0x56,0x7E,0x1B,0x34,0xC3,0xD6,0xA5,
|
||||
0xC0,0xCE,0xAA,0x1A,0x0F,0x36,0x82,0x13,
|
||||
0xC3,0xD1,0x98,0x43,0xD0,0xB4,0xB0,0x9D,
|
||||
0xCB,0x9F,0xC7,0x2D,0x39,0xC8,0xDE,0x41,
|
||||
0xF1,0xBF,0x14,0xD4,0xBB,0x45,0x63,0xCA,
|
||||
0x28,0x37,0x16,0x21,0xCA,0xD3,0x32,0x4B,
|
||||
0x6A,0x2D,0x39,0x21,0x45,0xBE,0xBF,0xAC,
|
||||
0x74,0x88,0x05,0x23,0x6F,0x5C,0xA2,0xFE,
|
||||
0x92,0xB8,0x71,0xCD,0x8F,0x9C,0x36,0xD3,
|
||||
0x29,0x2B,0x55,0x09,0xCA,0x8C,0xAA,0x77,
|
||||
0xA2,0xAD,0xFC,0x7B,0xFD,0x77,0xDD,0xA6,
|
||||
0xF7,0x11,0x25,0xA7,0x45,0x6F,0xEA,0x15,
|
||||
0x3E,0x43,0x32,0x56,0xA2,0x26,0x1C,0x6A,
|
||||
0x06,0xED,0x36,0x93,0x79,0x7E,0x79,0x95,
|
||||
0xFA,0xD5,0xAA,0xBB,0xCF,0xBE,0x3E,0xDA,
|
||||
0x27,0x41,0xE3,0x75,0x40,0x4A,0xE2,0x5B];
|
||||
let qbytes = vec![0xF2,0xC3,0x11,0x93,0x74,0xCE,0x76,0xC9,
|
||||
0x35,0x69,0x90,0xB4,0x65,0x37,0x4A,0x17,
|
||||
0xF2,0x3F,0x9E,0xD3,0x50,0x89,0xBD,0x96,
|
||||
0x9F,0x61,0xC6,0xDD,0xE9,0x99,0x8C,0x1F];
|
||||
let gbytes = vec![0x5C,0x7F,0xF6,0xB0,0x6F,0x8F,0x14,0x3F,
|
||||
0xE8,0x28,0x84,0x33,0x49,0x3E,0x47,0x69,
|
||||
0xC4,0xD9,0x88,0xAC,0xE5,0xBE,0x25,0xA0,
|
||||
0xE2,0x48,0x09,0x67,0x07,0x16,0xC6,0x13,
|
||||
0xD7,0xB0,0xCE,0xE6,0x93,0x2F,0x8F,0xAA,
|
||||
0x7C,0x44,0xD2,0xCB,0x24,0x52,0x3D,0xA5,
|
||||
0x3F,0xBE,0x4F,0x6E,0xC3,0x59,0x58,0x92,
|
||||
0xD1,0xAA,0x58,0xC4,0x32,0x8A,0x06,0xC4,
|
||||
0x6A,0x15,0x66,0x2E,0x7E,0xAA,0x70,0x3A,
|
||||
0x1D,0xEC,0xF8,0xBB,0xB2,0xD0,0x5D,0xBE,
|
||||
0x2E,0xB9,0x56,0xC1,0x42,0xA3,0x38,0x66,
|
||||
0x1D,0x10,0x46,0x1C,0x0D,0x13,0x54,0x72,
|
||||
0x08,0x50,0x57,0xF3,0x49,0x43,0x09,0xFF,
|
||||
0xA7,0x3C,0x61,0x1F,0x78,0xB3,0x2A,0xDB,
|
||||
0xB5,0x74,0x0C,0x36,0x1C,0x9F,0x35,0xBE,
|
||||
0x90,0x99,0x7D,0xB2,0x01,0x4E,0x2E,0xF5,
|
||||
0xAA,0x61,0x78,0x2F,0x52,0xAB,0xEB,0x8B,
|
||||
0xD6,0x43,0x2C,0x4D,0xD0,0x97,0xBC,0x54,
|
||||
0x23,0xB2,0x85,0xDA,0xFB,0x60,0xDC,0x36,
|
||||
0x4E,0x81,0x61,0xF4,0xA2,0xA3,0x5A,0xCA,
|
||||
0x3A,0x10,0xB1,0xC4,0xD2,0x03,0xCC,0x76,
|
||||
0xA4,0x70,0xA3,0x3A,0xFD,0xCB,0xDD,0x92,
|
||||
0x95,0x98,0x59,0xAB,0xD8,0xB5,0x6E,0x17,
|
||||
0x25,0x25,0x2D,0x78,0xEA,0xC6,0x6E,0x71,
|
||||
0xBA,0x9A,0xE3,0xF1,0xDD,0x24,0x87,0x19,
|
||||
0x98,0x74,0x39,0x3C,0xD4,0xD8,0x32,0x18,
|
||||
0x68,0x00,0x65,0x47,0x60,0xE1,0xE3,0x4C,
|
||||
0x09,0xE4,0xD1,0x55,0x17,0x9F,0x9E,0xC0,
|
||||
0xDC,0x44,0x73,0xF9,0x96,0xBD,0xCE,0x6E,
|
||||
0xED,0x1C,0xAB,0xED,0x8B,0x6F,0x11,0x6F,
|
||||
0x7A,0xD9,0xCF,0x50,0x5D,0xF0,0xF9,0x98,
|
||||
0xE3,0x4A,0xB2,0x75,0x14,0xB0,0xFF,0xE7];
|
||||
let xbytes = vec![0x69,0xC7,0x54,0x8C,0x21,0xD0,0xDF,0xEA,
|
||||
0x6B,0x9A,0x51,0xC9,0xEA,0xD4,0xE2,0x7C,
|
||||
0x33,0xD3,0xB3,0xF1,0x80,0x31,0x6E,0x5B,
|
||||
0xCA,0xB9,0x2C,0x93,0x3F,0x0E,0x4D,0xBC];
|
||||
let ybytes = vec![0x66,0x70,0x98,0xC6,0x54,0x42,0x6C,0x78,
|
||||
0xD7,0xF8,0x20,0x1E,0xAC,0x6C,0x20,0x3E,
|
||||
0xF0,0x30,0xD4,0x36,0x05,0x03,0x2C,0x2F,
|
||||
0x1F,0xA9,0x37,0xE5,0x23,0x7D,0xBD,0x94,
|
||||
0x9F,0x34,0xA0,0xA2,0x56,0x4F,0xE1,0x26,
|
||||
0xDC,0x8B,0x71,0x5C,0x51,0x41,0x80,0x2C,
|
||||
0xE0,0x97,0x9C,0x82,0x46,0x46,0x3C,0x40,
|
||||
0xE6,0xB6,0xBD,0xAA,0x25,0x13,0xFA,0x61,
|
||||
0x17,0x28,0x71,0x6C,0x2E,0x4F,0xD5,0x3B,
|
||||
0xC9,0x5B,0x89,0xE6,0x99,0x49,0xD9,0x65,
|
||||
0x12,0xE8,0x73,0xB9,0xC8,0xF8,0xDF,0xD4,
|
||||
0x99,0xCC,0x31,0x28,0x82,0x56,0x1A,0xDE,
|
||||
0xCB,0x31,0xF6,0x58,0xE9,0x34,0xC0,0xC1,
|
||||
0x97,0xF2,0xC4,0xD9,0x6B,0x05,0xCB,0xAD,
|
||||
0x67,0x38,0x1E,0x7B,0x76,0x88,0x91,0xE4,
|
||||
0xDA,0x38,0x43,0xD2,0x4D,0x94,0xCD,0xFB,
|
||||
0x51,0x26,0xE9,0xB8,0xBF,0x21,0xE8,0x35,
|
||||
0x8E,0xE0,0xE0,0xA3,0x0E,0xF1,0x3F,0xD6,
|
||||
0xA6,0x64,0xC0,0xDC,0xE3,0x73,0x1F,0x7F,
|
||||
0xB4,0x9A,0x48,0x45,0xA4,0xFD,0x82,0x54,
|
||||
0x68,0x79,0x72,0xA2,0xD3,0x82,0x59,0x9C,
|
||||
0x9B,0xAC,0x4E,0x0E,0xD7,0x99,0x81,0x93,
|
||||
0x07,0x89,0x13,0x03,0x25,0x58,0x13,0x49,
|
||||
0x76,0x41,0x0B,0x89,0xD2,0xC1,0x71,0xD1,
|
||||
0x23,0xAC,0x35,0xFD,0x97,0x72,0x19,0x59,
|
||||
0x7A,0xA7,0xD1,0x5C,0x1A,0x9A,0x42,0x8E,
|
||||
0x59,0x19,0x4F,0x75,0xC7,0x21,0xEB,0xCB,
|
||||
0xCF,0xAE,0x44,0x69,0x6A,0x49,0x9A,0xFA,
|
||||
0x74,0xE0,0x42,0x99,0xF1,0x32,0x02,0x66,
|
||||
0x01,0x63,0x8C,0xB8,0x7A,0xB7,0x91,0x90,
|
||||
0xD4,0xA0,0x98,0x63,0x15,0xDA,0x8E,0xEC,
|
||||
0x65,0x61,0xC9,0x38,0x99,0x6B,0xEA,0xDF];
|
||||
//
|
||||
let p = UCN::from_bytes(&pbytes);
|
||||
let q = UCN::from_bytes(&qbytes);
|
||||
let g = UCN::from_bytes(&gbytes);
|
||||
let params = DSAParameters::new(p, g, q).unwrap();
|
||||
let x = UCN::from_bytes(&xbytes);
|
||||
let y = UCN::from_bytes(&ybytes);
|
||||
let private = DSAPrivate::new(¶ms, x);
|
||||
let public = DSAPublic::new(¶ms, y);
|
||||
//
|
||||
let sample: [u8; 6] = [115, 97, 109, 112, 108, 101]; // "sample", ASCII
|
||||
let test: [u8; 4] = [116, 101, 115, 116]; // "test", ASCII
|
||||
// With SHA-1, message = "sample":
|
||||
// k = 888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E
|
||||
// r = 3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A
|
||||
// s = D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF
|
||||
run_rfc6979_test!(Sha1, sample, public, private,
|
||||
k vec![0x88,0x8F,0xA6,0xF7,0x73,0x8A,0x41,0xBD,
|
||||
0xC9,0x84,0x64,0x66,0xAB,0xDB,0x81,0x74,
|
||||
0xC0,0x33,0x82,0x50,0xAE,0x50,0xCE,0x95,
|
||||
0x5C,0xA1,0x62,0x30,0xF9,0xCB,0xD5,0x3E],
|
||||
r vec![0x3A,0x1B,0x2D,0xBD,0x74,0x89,0xD6,0xED,
|
||||
0x7E,0x60,0x8F,0xD0,0x36,0xC8,0x3A,0xF3,
|
||||
0x96,0xE2,0x90,0xDB,0xD6,0x02,0x40,0x8E,
|
||||
0x86,0x77,0xDA,0xAB,0xD6,0xE7,0x44,0x5A],
|
||||
s vec![0xD2,0x6F,0xCB,0xA1,0x9F,0xA3,0xE3,0x05,
|
||||
0x8F,0xFC,0x02,0xCA,0x15,0x96,0xCD,0xBB,
|
||||
0x6E,0x0D,0x20,0xCB,0x37,0xB0,0x60,0x54,
|
||||
0xF7,0xE3,0x6D,0xED,0x0C,0xDB,0xBC,0xCF]);
|
||||
// With SHA-224, message = "sample":
|
||||
// k = BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806
|
||||
// r = DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C
|
||||
// s = A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC
|
||||
run_rfc6979_test!(Sha224, sample, public, private,
|
||||
k vec![0xBC,0x37,0x29,0x67,0x70,0x20,0x82,0xE1,
|
||||
0xAA,0x4F,0xCE,0x89,0x22,0x09,0xF7,0x1A,
|
||||
0xE4,0xAD,0x25,0xA6,0xDF,0xD8,0x69,0x33,
|
||||
0x4E,0x6F,0x15,0x3B,0xD0,0xC4,0xD8,0x06],
|
||||
r vec![0xDC,0x9F,0x4D,0xEA,0xDA,0x8D,0x8F,0xF5,
|
||||
0x88,0xE9,0x8F,0xED,0x0A,0xB6,0x90,0xFF,
|
||||
0xCE,0x85,0x8D,0xC8,0xC7,0x93,0x76,0x45,
|
||||
0x0E,0xB6,0xB7,0x6C,0x24,0x53,0x7E,0x2C],
|
||||
s vec![0xA6,0x5A,0x9C,0x3B,0xC7,0xBA,0xBE,0x28,
|
||||
0x6B,0x19,0x5D,0x5D,0xA6,0x86,0x16,0xDA,
|
||||
0x8D,0x47,0xFA,0x00,0x97,0xF3,0x6D,0xD1,
|
||||
0x9F,0x51,0x73,0x27,0xDC,0x84,0x8C,0xEC]);
|
||||
// With SHA-256, message = "sample":
|
||||
// k = 8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52
|
||||
// r = EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809
|
||||
// s = 7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53
|
||||
run_rfc6979_test!(Sha256, sample, public, private,
|
||||
k vec![0x89,0x26,0xA2,0x7C,0x40,0x48,0x42,0x16,
|
||||
0xF0,0x52,0xF4,0x42,0x7C,0xFD,0x56,0x47,
|
||||
0x33,0x8B,0x7B,0x39,0x39,0xBC,0x65,0x73,
|
||||
0xAF,0x43,0x33,0x56,0x9D,0x59,0x7C,0x52],
|
||||
r vec![0xEA,0xCE,0x8B,0xDB,0xBE,0x35,0x3C,0x43,
|
||||
0x2A,0x79,0x5D,0x9E,0xC5,0x56,0xC6,0xD0,
|
||||
0x21,0xF7,0xA0,0x3F,0x42,0xC3,0x6E,0x9B,
|
||||
0xC8,0x7E,0x4A,0xC7,0x93,0x2C,0xC8,0x09],
|
||||
s vec![0x70,0x81,0xE1,0x75,0x45,0x5F,0x92,0x47,
|
||||
0xB8,0x12,0xB7,0x45,0x83,0xE9,0xE9,0x4F,
|
||||
0x9E,0xA7,0x9B,0xD6,0x40,0xDC,0x96,0x25,
|
||||
0x33,0xB0,0x68,0x07,0x93,0xA3,0x8D,0x53]);
|
||||
// With SHA-384, message = "sample":
|
||||
// k = C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920
|
||||
// r = B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B
|
||||
// s = 19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B
|
||||
run_rfc6979_test!(Sha384, sample, public, private,
|
||||
k vec![0xC3,0x45,0xD5,0xAB,0x3D,0xA0,0xA5,0xBC,
|
||||
0xB7,0xEC,0x8F,0x8F,0xB7,0xA7,0xE9,0x60,
|
||||
0x69,0xE0,0x3B,0x20,0x63,0x71,0xEF,0x7D,
|
||||
0x83,0xE3,0x90,0x68,0xEC,0x56,0x49,0x20],
|
||||
r vec![0xB2,0xDA,0x94,0x5E,0x91,0x85,0x88,0x34,
|
||||
0xFD,0x9B,0xF6,0x16,0xEB,0xAC,0x15,0x1E,
|
||||
0xDB,0xC4,0xB4,0x5D,0x27,0xD0,0xDD,0x4A,
|
||||
0x7F,0x6A,0x22,0x73,0x9F,0x45,0xC0,0x0B],
|
||||
s vec![0x19,0x04,0x8B,0x63,0xD9,0xFD,0x6B,0xCA,
|
||||
0x1D,0x9B,0xAE,0x36,0x64,0xE1,0xBC,0xB9,
|
||||
0x7F,0x72,0x76,0xC3,0x06,0x13,0x09,0x69,
|
||||
0xF6,0x3F,0x38,0xFA,0x83,0x19,0x02,0x1B]);
|
||||
// With SHA-512, message = "sample":
|
||||
// k = 5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC
|
||||
// r = 2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E
|
||||
// s = D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351
|
||||
run_rfc6979_test!(Sha512, sample, public, private,
|
||||
k vec![0x5A,0x12,0x99,0x44,0x31,0x78,0x54,0x85,
|
||||
0xB3,0xF5,0xF0,0x67,0x22,0x15,0x17,0x79,
|
||||
0x1B,0x85,0xA5,0x97,0xB7,0xA9,0x43,0x69,
|
||||
0x95,0xC8,0x9E,0xD0,0x37,0x46,0x68,0xFC],
|
||||
r vec![0x20,0x16,0xED,0x09,0x2D,0xC5,0xFB,0x66,
|
||||
0x9B,0x8E,0xFB,0x3D,0x1F,0x31,0xA9,0x1E,
|
||||
0xEC,0xB1,0x99,0x87,0x9B,0xE0,0xCF,0x78,
|
||||
0xF0,0x2B,0xA0,0x62,0xCB,0x4C,0x94,0x2E],
|
||||
s vec![0xD0,0xC7,0x6F,0x84,0xB5,0xF0,0x91,0xE1,
|
||||
0x41,0x57,0x2A,0x63,0x9A,0x4F,0xB8,0xC2,
|
||||
0x30,0x80,0x7E,0xEA,0x7D,0x55,0xC8,0xA1,
|
||||
0x54,0xA2,0x24,0x40,0x0A,0xFF,0x23,0x51]);
|
||||
// With SHA-1, message = "test":
|
||||
// k = 6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F
|
||||
// r = C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0
|
||||
// s = 414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA
|
||||
run_rfc6979_test!(Sha1, test, public, private,
|
||||
k vec![0x6E,0xEA,0x48,0x6F,0x9D,0x41,0xA0,0x37,
|
||||
0xB2,0xC6,0x40,0xBC,0x56,0x45,0x69,0x4F,
|
||||
0xF8,0xFF,0x4B,0x98,0xD0,0x66,0xA2,0x5F,
|
||||
0x76,0xBE,0x64,0x1C,0xCB,0x24,0xBA,0x4F],
|
||||
r vec![0xC1,0x82,0x70,0xA9,0x3C,0xFC,0x60,0x63,
|
||||
0xF5,0x7A,0x4D,0xFA,0x86,0x02,0x4F,0x70,
|
||||
0x0D,0x98,0x0E,0x4C,0xF4,0xE2,0xCB,0x65,
|
||||
0xA5,0x04,0x39,0x72,0x73,0xD9,0x8E,0xA0],
|
||||
s vec![0x41,0x4F,0x22,0xE5,0xF3,0x1A,0x8B,0x6D,
|
||||
0x33,0x29,0x5C,0x75,0x39,0xC1,0xC1,0xBA,
|
||||
0x3A,0x61,0x60,0xD7,0xD6,0x8D,0x50,0xAC,
|
||||
0x0D,0x3A,0x5B,0xEA,0xC2,0x88,0x4F,0xAA]);
|
||||
// With SHA-224, message = "test":
|
||||
// k = 06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670
|
||||
// r = 272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3
|
||||
// s = E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806
|
||||
run_rfc6979_test!(Sha224, test, public, private,
|
||||
k vec![0x06,0xBD,0x4C,0x05,0xED,0x74,0x71,0x91,
|
||||
0x06,0x22,0x3B,0xE3,0x3F,0x2D,0x95,0xDA,
|
||||
0x6B,0x3B,0x54,0x1D,0xAD,0x7B,0xFB,0xD7,
|
||||
0xAC,0x50,0x82,0x13,0xB6,0xDA,0x66,0x70],
|
||||
r vec![0x27,0x2A,0xBA,0x31,0x57,0x2F,0x6C,0xC5,
|
||||
0x5E,0x30,0xBF,0x61,0x6B,0x7A,0x26,0x53,
|
||||
0x12,0x01,0x8D,0xD3,0x25,0xBE,0x03,0x1B,
|
||||
0xE0,0xCC,0x82,0xAA,0x17,0x87,0x0E,0xA3],
|
||||
s vec![0xE9,0xCC,0x28,0x6A,0x52,0xCC,0xE2,0x01,
|
||||
0x58,0x67,0x22,0xD3,0x6D,0x1E,0x91,0x7E,
|
||||
0xB9,0x6A,0x4E,0xBD,0xB4,0x79,0x32,0xF9,
|
||||
0x57,0x6A,0xC6,0x45,0xB3,0xA6,0x08,0x06]);
|
||||
// With SHA-256, message = "test":
|
||||
// k = 1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7
|
||||
// r = 8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0
|
||||
// s = 7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E
|
||||
run_rfc6979_test!(Sha256, test, public, private,
|
||||
k vec![0x1D,0x6C,0xE6,0xDD,0xA1,0xC5,0xD3,0x73,
|
||||
0x07,0x83,0x9C,0xD0,0x3A,0xB0,0xA5,0xCB,
|
||||
0xB1,0x8E,0x60,0xD8,0x00,0x93,0x7D,0x67,
|
||||
0xDF,0xB4,0x47,0x9A,0xAC,0x8D,0xEA,0xD7],
|
||||
r vec![0x81,0x90,0x01,0x2A,0x19,0x69,0xF9,0x95,
|
||||
0x7D,0x56,0xFC,0xCA,0xAD,0x22,0x31,0x86,
|
||||
0xF4,0x23,0x39,0x8D,0x58,0xEF,0x5B,0x3C,
|
||||
0xEF,0xD5,0xA4,0x14,0x6A,0x44,0x76,0xF0],
|
||||
s vec![0x74,0x52,0xA5,0x3F,0x70,0x75,0xD4,0x17,
|
||||
0xB4,0xB0,0x13,0xB2,0x78,0xD1,0xBB,0x8B,
|
||||
0xBD,0x21,0x86,0x3F,0x5E,0x7B,0x1C,0xEE,
|
||||
0x67,0x9C,0xF2,0x18,0x8E,0x1A,0xB1,0x9E]);
|
||||
// With SHA-384, message = "test":
|
||||
// k = 206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C
|
||||
// r = 239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE
|
||||
// s = 6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961
|
||||
run_rfc6979_test!(Sha384, test, public, private,
|
||||
k vec![0x20,0x6E,0x61,0xF7,0x3D,0xBE,0x1B,0x2D,
|
||||
0xC8,0xBE,0x73,0x6B,0x22,0xB0,0x79,0xE9,
|
||||
0xDA,0xCD,0x97,0x4D,0xB0,0x0E,0xEB,0xBC,
|
||||
0x5B,0x64,0xCA,0xD3,0x9C,0xF9,0xF9,0x1C],
|
||||
r vec![0x23,0x9E,0x66,0xDD,0xBE,0x8F,0x8C,0x23,
|
||||
0x0A,0x3D,0x07,0x1D,0x60,0x1B,0x6F,0xFB,
|
||||
0xDF,0xB5,0x90,0x1F,0x94,0xD4,0x44,0xC6,
|
||||
0xAF,0x56,0xF7,0x32,0xBE,0xB9,0x54,0xBE],
|
||||
s vec![0x6B,0xD7,0x37,0x51,0x3D,0x5E,0x72,0xFE,
|
||||
0x85,0xD1,0xC7,0x50,0xE0,0xF7,0x39,0x21,
|
||||
0xFE,0x29,0x9B,0x94,0x5A,0xAD,0x1C,0x80,
|
||||
0x2F,0x15,0xC2,0x6A,0x43,0xD3,0x49,0x61]);
|
||||
// With SHA-512, message = "test":
|
||||
// k = AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA
|
||||
// r = 89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307
|
||||
// s = C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1
|
||||
run_rfc6979_test!(Sha512, test, public, private,
|
||||
k vec![0xAF,0xF1,0x65,0x1E,0x4C,0xD6,0x03,0x6D,
|
||||
0x57,0xAA,0x8B,0x2A,0x05,0xCC,0xF1,0xA9,
|
||||
0xD5,0xA4,0x01,0x66,0x34,0x0E,0xCB,0xBD,
|
||||
0xC5,0x5B,0xE1,0x0B,0x56,0x8A,0xA0,0xAA],
|
||||
r vec![0x89,0xEC,0x4B,0xB1,0x40,0x0E,0xCC,0xFF,
|
||||
0x8E,0x7D,0x9A,0xA5,0x15,0xCD,0x1D,0xE7,
|
||||
0x80,0x3F,0x2D,0xAF,0xF0,0x96,0x93,0xEE,
|
||||
0x7F,0xD1,0x35,0x3E,0x90,0xA6,0x83,0x07],
|
||||
s vec![0xC9,0xF0,0xBD,0xAB,0xCC,0x0D,0x88,0x0B,
|
||||
0xB1,0x37,0xA9,0x94,0xCC,0x7F,0x39,0x80,
|
||||
0xCE,0x91,0xCC,0x10,0xFA,0xF5,0x29,0xFC,
|
||||
0x46,0x56,0x5B,0x15,0xCE,0xA8,0x54,0xE1]);
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
mod errors;
|
||||
mod generation;
|
||||
#[cfg(test)]
|
||||
mod gold_tests;
|
||||
mod parameters;
|
||||
mod public;
|
||||
mod private;
|
||||
pub(crate) mod rfc6979;
|
||||
|
||||
pub use self::public::DSAPublic;
|
||||
pub use self::private::DSAPrivate;
|
||||
pub use self::rfc6979::DSASignature;
|
||||
|
||||
use cryptonum::UCN;
|
||||
use rand::{OsRng,Rng};
|
||||
use self::errors::*;
|
||||
use self::parameters::*;
|
||||
|
||||
/// A DSA key pair
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct DSAKeyPair {
|
||||
pub private: DSAPrivate,
|
||||
pub public: DSAPublic
|
||||
}
|
||||
|
||||
impl DSAKeyPair {
|
||||
pub fn generate(size: DSAParameterSize)
|
||||
-> Result<DSAKeyPair,DSAGenError>
|
||||
{
|
||||
let mut rng = OsRng::new()?;
|
||||
DSAKeyPair::generate_rng(&mut rng, size)
|
||||
}
|
||||
|
||||
pub fn generate_rng<G: Rng>(rng: &mut G, size: DSAParameterSize)
|
||||
-> Result<DSAKeyPair,DSAGenError>
|
||||
{
|
||||
let params = DSAParameters::generate_w_rng(rng, size)?;
|
||||
DSAKeyPair::generate_w_params_rng(rng, ¶ms)
|
||||
}
|
||||
|
||||
pub fn generate_w_params(params: &DSAParameters)
|
||||
-> Result<DSAKeyPair,DSAGenError>
|
||||
{
|
||||
let mut rng = OsRng::new()?;
|
||||
DSAKeyPair::generate_w_params_rng(&mut rng, params)
|
||||
}
|
||||
|
||||
pub fn generate_w_params_rng<G: Rng>(rng: &mut G, params: &DSAParameters)
|
||||
-> Result<DSAKeyPair,DSAGenError>
|
||||
{
|
||||
// 1. N = len(q); L = len(p);
|
||||
let n = n_bits(params.size);
|
||||
// 2. If the (L,N) pair is invalid, then return an ERROR indicator,
|
||||
// Invalid_x, and Invalid_y.
|
||||
// 3. requested_security_strength = the security strength associated
|
||||
// with the (L, N) pair; see SP 800-57.
|
||||
// 4. Obtain a string of N+64 returned_bits from an RBG with a security
|
||||
// strength of requested_security_strength or more. If an ERROR
|
||||
// indication is returned, then return an ERROR indication,
|
||||
// Invalid_x, and Invalid_y.
|
||||
let returned_bits: Vec<u8> = rng.gen_iter().take(n + 8).collect();
|
||||
// 5. Convert returned_bits to the (non-negative) integer c.
|
||||
let c = UCN::from_bytes(&returned_bits);
|
||||
// 6. x = (c mod (q-1)) + 1.
|
||||
let one = UCN::from(1 as u64);
|
||||
let x = (&c % (¶ms.q - &one)) + &one;
|
||||
// 7. y = g^x mod p
|
||||
let y = params.g.fastmodexp(&x, ¶ms.pu);
|
||||
// 8. Return SUCCESS, x, and y.
|
||||
let private = DSAPrivate { params: params.clone(), x: x };
|
||||
let public = DSAPublic { params: params.clone(), y: y };
|
||||
Ok(DSAKeyPair {
|
||||
private: private,
|
||||
public: public
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
use cryptonum::{BarrettUCN,UCN};
|
||||
use dsa::errors::*;
|
||||
use dsa::generation::{DSAGenEvidence,verify_generator,
|
||||
get_input_seed,generate_provable_primes,
|
||||
generate_verifiable_generator,
|
||||
validate_provable_primes};
|
||||
use rand::{OsRng,Rng};
|
||||
|
||||
/// These are the legal lengths for L and N when using DSA; essentially,
|
||||
/// the bit sizes available for the algorithms.
|
||||
#[derive(Clone,Copy,Debug,PartialEq)]
|
||||
pub enum DSAParameterSize { L1024N160, L2048N224, L2048N256, L3072N256 }
|
||||
|
||||
pub fn n_bits(ps: DSAParameterSize) -> usize {
|
||||
match ps {
|
||||
DSAParameterSize::L1024N160 => 160,
|
||||
DSAParameterSize::L2048N224 => 224,
|
||||
DSAParameterSize::L2048N256 => 256,
|
||||
DSAParameterSize::L3072N256 => 256,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn l_bits(ps: DSAParameterSize) -> usize {
|
||||
match ps {
|
||||
DSAParameterSize::L1024N160 => 1024,
|
||||
DSAParameterSize::L2048N224 => 2048,
|
||||
DSAParameterSize::L2048N256 => 2048,
|
||||
DSAParameterSize::L3072N256 => 3072,
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of DSA parameters, which are shared across both the public and private
|
||||
/// keys.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct DSAParameters {
|
||||
pub size: DSAParameterSize,
|
||||
pub p: UCN,
|
||||
pub g: UCN,
|
||||
pub q: UCN,
|
||||
pub pu: BarrettUCN,
|
||||
pub qu: BarrettUCN
|
||||
}
|
||||
|
||||
impl DSAParameters {
|
||||
/// Generate a new set of DSA parameters, from a certificate file or some
|
||||
/// other source. This will try to find an appropriate size based on the
|
||||
/// size of the values provided, but will fail (returning
|
||||
/// `DSAError::InvalidParamSize`) if it can't find a reasonable one.
|
||||
pub fn new(p: UCN, g: UCN, q: UCN)
|
||||
-> Result<DSAParameters,DSAError>
|
||||
{
|
||||
let l = ((p.bits() + 255) / 256) * 256;
|
||||
let n = ((q.bits() + 15) / 16) * 16;
|
||||
let size = match (l, n) {
|
||||
(1024, 160) => DSAParameterSize::L1024N160,
|
||||
(2048, 224) => DSAParameterSize::L2048N224,
|
||||
(2048, 256) => DSAParameterSize::L2048N256,
|
||||
(3072, 256) => DSAParameterSize::L3072N256,
|
||||
_ => return Err(DSAError::InvalidParamSize)
|
||||
};
|
||||
let pu = p.barrett_u();
|
||||
let qu = q.barrett_u();
|
||||
Ok(DSAParameters{ size: size, p: p, g: g, q: q, pu: pu, qu: qu })
|
||||
}
|
||||
|
||||
/// Generate a new set of DSA parameters for use. You probably shouldn't be
|
||||
/// doing this. This is equivalent to calling `generate_w_rng` with
|
||||
/// `OsRng`, which is supposed to be cryptographically sound.
|
||||
pub fn generate(ps: DSAParameterSize)
|
||||
-> Result<DSAParameters,DSAGenError>
|
||||
{
|
||||
let mut rng = OsRng::new()?;
|
||||
DSAParameters::generate_w_rng(&mut rng, ps)
|
||||
}
|
||||
|
||||
/// Generate a new set of DSA parameters for use, using the given entropy
|
||||
/// source. I would normally include a note here about making sure to use
|
||||
/// a good one, but if you're using DSA you've already given up a little
|
||||
/// bit of the high ground, there.
|
||||
pub fn generate_w_rng<G: Rng>(rng: &mut G, ps: DSAParameterSize)
|
||||
-> Result<DSAParameters,DSAGenError>
|
||||
{
|
||||
let firstseed = get_input_seed(rng, ps, n_bits(ps))?;
|
||||
let (p, q, ev) = generate_provable_primes(rng, &firstseed, ps)?;
|
||||
DSAParameters::generate_g(ps, p, q, ev, 0)
|
||||
}
|
||||
|
||||
/// Using the given p and q values and an index, create a new DSAParameters
|
||||
/// by creating a new generator g that works with p and q.
|
||||
fn generate_g(ps: DSAParameterSize,
|
||||
p: UCN, q: UCN,
|
||||
ev: DSAGenEvidence,
|
||||
idx: u8)
|
||||
-> Result<DSAParameters, DSAGenError>
|
||||
{
|
||||
let pu = p.barrett_u();
|
||||
let qu = q.barrett_u();
|
||||
let g = generate_verifiable_generator(&p, &pu, &q, &ev, idx)?;
|
||||
Ok(DSAParameters{ size: ps, p: p, q: q, g: g, pu: pu, qu: qu })
|
||||
}
|
||||
|
||||
/// Given the provided evidence, validate that the domain parameters
|
||||
/// were appropriately constructed.
|
||||
pub fn verify(&self, ev: &DSAGenEvidence, idx: u8) -> bool {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
self.verify_w_rng(&mut rng, ev, idx)
|
||||
}
|
||||
|
||||
/// Given the set of inputs you used to generate your system, verify that
|
||||
/// everything makes sense.
|
||||
pub fn verify_w_rng<G: Rng>(&self, r: &mut G, ev: &DSAGenEvidence, idx: u8)
|
||||
-> bool
|
||||
{
|
||||
validate_provable_primes(r, &self.p, &self.q, ev) &&
|
||||
verify_generator(&self.p, &self.q, ev, idx, &self.g)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
use cryptonum::UCN;
|
||||
use digest::{BlockInput,FixedOutput,Input};
|
||||
use digest::generic_array::ArrayLength;
|
||||
use dsa::parameters::{DSAParameters,n_bits};
|
||||
use dsa::rfc6979::{DSASignature,KIterator,bits2int};
|
||||
use hmac::Hmac;
|
||||
use std::ops::Rem;
|
||||
|
||||
/// A DSA private key.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct DSAPrivate {
|
||||
pub params: DSAParameters,
|
||||
pub(crate) x: UCN
|
||||
}
|
||||
|
||||
impl DSAPrivate {
|
||||
pub fn new(params: &DSAParameters, x: UCN) -> DSAPrivate {
|
||||
DSAPrivate {
|
||||
params: params.clone(),
|
||||
x: x
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature
|
||||
where
|
||||
Hash: Clone + BlockInput + Input + FixedOutput + Default,
|
||||
Hmac<Hash>: Clone,
|
||||
Hash::BlockSize: ArrayLength<u8>
|
||||
{
|
||||
// This algorithm is per RFC 6979, which has a nice, relatively
|
||||
// straightforward description of how to do DSA signing.
|
||||
//
|
||||
// 1. H(m) is transformed into an integer modulo q using the bits2int
|
||||
// transform and an extra modular reduction:
|
||||
//
|
||||
// h = bits2int(H(m)) mod q
|
||||
//
|
||||
// As was noted in the description of bits2octets, the extra
|
||||
// modular reduction is no more than a conditional subtraction.
|
||||
//
|
||||
let mut digest = <Hash>::default();
|
||||
digest.process(m);
|
||||
let n = n_bits(self.params.size);
|
||||
let h1: Vec<u8> = digest.fixed_result()
|
||||
.as_slice()
|
||||
.iter()
|
||||
.map(|x| *x)
|
||||
.collect();
|
||||
let h0 = bits2int(&h1, n);
|
||||
let h = h0.reduce(&self.params.qu);
|
||||
|
||||
// 2. A random value modulo q, dubbed k, is generated. That value
|
||||
// shall not be 0; hence, it lies in the [1, q-1] range. Most
|
||||
// of the remainder of this document will revolve around the
|
||||
// process used to generate k. In plain DSA or ECDSA, k should
|
||||
// be selected through a random selection that chooses a value
|
||||
// among the q-1 possible values with uniform probability.
|
||||
for k in KIterator::<Hash>::new(&h1, n, &self.params.q, &self.x) {
|
||||
// 3. A value r (modulo q) is computed from k and the key
|
||||
// parameters:
|
||||
// * For DSA:
|
||||
// r = g^k mod p mod q
|
||||
//
|
||||
// (The exponentiation is performed modulo p, yielding a
|
||||
// number between 0 and p-1, which is then further reduced
|
||||
// modulo q.)
|
||||
// * For ECDSA ...
|
||||
//
|
||||
// If r turns out to be zero, a new k should be selected and r
|
||||
// computed again (this is an utterly improbable occurrence).
|
||||
let r = self.params.g.fastmodexp(&k, &self.params.pu)
|
||||
.rem(&self.params.q);
|
||||
if r.is_zero() {
|
||||
continue;
|
||||
}
|
||||
// 4. The value s (modulo q) is computed:
|
||||
//
|
||||
// s = (h+x*r)/k mod q
|
||||
//
|
||||
// The pair (r, s) is the signature.
|
||||
let kinv = k.modinv(&self.params.q);
|
||||
let s = ((&h + (&self.x * &r)) * &kinv).rem(&self.params.q);
|
||||
return DSASignature{ r: r, s: s };
|
||||
}
|
||||
panic!("The world is broken; couldn't find a k in sign().");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
use cryptonum::{SCN,UCN};
|
||||
use digest::{FixedOutput,Input};
|
||||
use dsa::parameters::{DSAParameters,n_bits};
|
||||
use dsa::rfc6979::DSASignature;
|
||||
use num::BigInt;
|
||||
use simple_asn1::{ASN1Block,ToASN1,ASN1EncodeErr,ASN1Class};
|
||||
use std::cmp::min;
|
||||
use std::ops::Rem;
|
||||
|
||||
/// A DSA key pair
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct DSAPublic {
|
||||
pub params: DSAParameters,
|
||||
pub y: UCN
|
||||
}
|
||||
|
||||
impl DSAPublic {
|
||||
pub fn new(params: &DSAParameters, y: UCN) -> DSAPublic {
|
||||
DSAPublic {
|
||||
params: params.clone(),
|
||||
y: y
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature) -> bool
|
||||
where Hash: Clone + Default + Input + FixedOutput
|
||||
{
|
||||
if sig.r >= self.params.q {
|
||||
return false;
|
||||
}
|
||||
if sig.s >= self.params.q {
|
||||
return false;
|
||||
}
|
||||
// w = (s')^-1 mod q;
|
||||
let w = sig.s.modinv(&self.params.q);
|
||||
// z = the leftmost min(N, outlen) bits of Hash(M').
|
||||
let mut digest = <Hash>::default();
|
||||
digest.process(m);
|
||||
let z = { let mut bytes: Vec<u8> = digest.fixed_result()
|
||||
.as_slice()
|
||||
.iter()
|
||||
.map(|x| *x)
|
||||
.collect();
|
||||
let n = n_bits(self.params.size) / 8;
|
||||
let len = min(n, bytes.len());
|
||||
bytes.truncate(len);
|
||||
UCN::from_bytes(&bytes) };
|
||||
// u1 = (zw) mod q
|
||||
let u1 = (&z * &w).reduce(&self.params.qu);
|
||||
// u2 = (rw) mod q
|
||||
let u2 = (&sig.r * &w).reduce(&self.params.qu);
|
||||
// v = (((g)^u1(y)^u2) mod p) mod q
|
||||
let v_1 = self.params.g.fastmodexp(&u1, &self.params.pu);
|
||||
let v_2 = self.y.fastmodexp(&u2, &self.params.pu);
|
||||
let v = (&v_1 * &v_2).reduce(&self.params.pu)
|
||||
.rem(&self.params.q);
|
||||
// if v = r, then the signature is verified
|
||||
v == sig.r
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for DSAPublic {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||
{
|
||||
let inty = SCN::from(self.y.clone());
|
||||
let yblock = ASN1Block::Integer(c, 0, BigInt::from(inty));
|
||||
Ok(vec![yblock])
|
||||
}
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
use cryptonum::UCN;
|
||||
use digest::{BlockInput,FixedOutput,Input};
|
||||
use digest::generic_array::ArrayLength;
|
||||
use hmac::{Hmac,Mac};
|
||||
use num::{BigInt,Signed};
|
||||
use simple_asn1::{ASN1Block,ASN1Class,ASN1DecodeErr,ASN1EncodeErr,
|
||||
FromASN1, ToASN1};
|
||||
use std::clone::Clone;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub struct KIterator<H>
|
||||
where
|
||||
H: Clone + BlockInput + Input + FixedOutput + Default,
|
||||
H::BlockSize : ArrayLength<u8>
|
||||
{
|
||||
hmac_k: Hmac<H>,
|
||||
V: Vec<u8>,
|
||||
q: UCN,
|
||||
qlen: usize
|
||||
}
|
||||
|
||||
impl<H> KIterator<H>
|
||||
where
|
||||
H: Clone + BlockInput + Input + FixedOutput + Default,
|
||||
Hmac<H>: Clone,
|
||||
H::BlockSize : ArrayLength<u8>
|
||||
{
|
||||
pub fn new(h1: &[u8], qlen: usize, q: &UCN, x: &UCN) -> KIterator<H>
|
||||
{
|
||||
// Given the input message m, the following process is applied:
|
||||
//
|
||||
// a. Process m through the hash function H, yielding:
|
||||
//
|
||||
// h1 = H(m)
|
||||
//
|
||||
// (h1 is a sequence of hlen bits).
|
||||
//
|
||||
let hlen = h1.len();
|
||||
// b. Set:
|
||||
//
|
||||
// V = 0x01 0x01 0x01 ... 0x01
|
||||
//
|
||||
// such that the length of V, in bits, is equal to 8*ceil(hlen/8).
|
||||
// For instance, on an octet-based system, if H is SHA-256, then
|
||||
// V is set to a sequence of 32 octets of value 1. Note that in
|
||||
// this step and all subsequent steps, we use the same H function
|
||||
// as the one used in step 'a' to process the input message; this
|
||||
// choice will be discussed in more detail in Section 3.6.
|
||||
//
|
||||
#[allow(non_snake_case)]
|
||||
let mut V = Vec::new();
|
||||
V.resize(hlen, 0x01);
|
||||
// c. Set:
|
||||
//
|
||||
// K = 0x00 0x00 0x00 ... 0x00
|
||||
//
|
||||
// such that the length of K, in bits, is equal to 8*ceil(hlen/8).
|
||||
#[allow(non_snake_case)]
|
||||
let mut K = Vec::new();
|
||||
K.resize(hlen, 0x00);
|
||||
// d. Set:
|
||||
//
|
||||
// K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1))
|
||||
//
|
||||
// where '||' denotes concatenation. In other words, we compute
|
||||
// HMAC with key K, over the concatenation of the following, in
|
||||
// order: the current value of V, a sequence of eight bits of value
|
||||
// 0, the encoding of the (EC)DSA private key x, and the hashed
|
||||
// message (possibly truncated and extended as specified by the
|
||||
// bits2octets transform). The HMAC result is the new value of K.
|
||||
// Note that the private key x is in the [1, q-1] range, hence a
|
||||
// proper input for int2octets, yielding rlen bits of output, i.e.,
|
||||
// an integral number of octets (rlen is a multiple of 8).
|
||||
let xbytes = int2octets(x, qlen);
|
||||
let h1bytes = bits2octets(h1, q, qlen);
|
||||
let mut input = Vec::new();
|
||||
input.extend_from_slice(&V);
|
||||
input.push(0x00);
|
||||
input.extend_from_slice(&xbytes);
|
||||
input.extend_from_slice(&h1bytes);
|
||||
K = hmac(&K, &input);
|
||||
// e. Set:
|
||||
//
|
||||
// V = HMAC_K(V)
|
||||
V = hmac(&K, &V);
|
||||
// f. Set:
|
||||
//
|
||||
// K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
|
||||
//
|
||||
// Note that the "internal octet" is 0x01 this time.
|
||||
input = Vec::new();
|
||||
input.extend_from_slice(&V);
|
||||
input.push(0x01);
|
||||
input.extend_from_slice(&xbytes);
|
||||
input.extend_from_slice(&h1bytes);
|
||||
K = hmac(&K, &input);
|
||||
// g. Set:
|
||||
//
|
||||
// V = HMAC_K(V)
|
||||
V = hmac(&K, &V);
|
||||
// h is for later ...
|
||||
KIterator {
|
||||
hmac_k: Hmac::<H>::new(&K).unwrap(),
|
||||
V: V,
|
||||
q: q.clone(),
|
||||
qlen: qlen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<H> Iterator for KIterator<H>
|
||||
where
|
||||
H: Clone + BlockInput + Input + FixedOutput + Default,
|
||||
Hmac<H>: Clone,
|
||||
H::BlockSize : ArrayLength<u8>
|
||||
{
|
||||
type Item = UCN;
|
||||
|
||||
fn next(&mut self) -> Option<UCN> {
|
||||
loop {
|
||||
// h. Apply the following algorithm until a proper value is found
|
||||
// for k:
|
||||
//
|
||||
// 1. Set T to the empty sequence. The length of T (in bits) is
|
||||
// denoted tlen; thus, at that point, tlen = 0.
|
||||
let mut t = Vec::new();
|
||||
//
|
||||
// 2. While tlen < qlen, do the following:
|
||||
//
|
||||
// V = HMAC_K(V)
|
||||
// T = T || V
|
||||
let target = (self.qlen + 7) / 8;
|
||||
while t.len() < target {
|
||||
self.V = runhmac(&self.hmac_k, &self.V);
|
||||
t.extend_from_slice(&self.V);
|
||||
}
|
||||
//
|
||||
// 3. Compute:
|
||||
//
|
||||
// k = bits2int(T)
|
||||
let resk = bits2int(&t, self.qlen);
|
||||
//
|
||||
// If that value of k is within the [1,q-1] range, and is
|
||||
// suitable for DSA or ECDSA (i.e., it results in an r value
|
||||
// that is not 0; see Section 3.4), then the generation of k
|
||||
// is finished. The obtained value of k is used in DSA or
|
||||
// ECDSA. Otherwise, compute:
|
||||
//
|
||||
// K = HMAC_K(V || 0x00)
|
||||
let mut input = self.V.clone();
|
||||
input.push(0x00);
|
||||
#[allow(non_snake_case)]
|
||||
let K = runhmac(&self.hmac_k, &input);
|
||||
// V = HMAC_K(V)
|
||||
self.hmac_k = Hmac::<H>::new(&K).unwrap();
|
||||
self.V = runhmac(&self.hmac_k, &self.V);
|
||||
//
|
||||
// and loop (try to generate a new T, and so on).
|
||||
//
|
||||
if !resk.is_zero() && (&resk < &self.q) {
|
||||
return Some(resk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bits2int(x: &[u8], qlen: usize) -> UCN {
|
||||
let mut value = UCN::from_bytes(x);
|
||||
let vlen = x.len() * 8;
|
||||
|
||||
if vlen > qlen {
|
||||
value >>= vlen - qlen;
|
||||
}
|
||||
|
||||
value
|
||||
}
|
||||
|
||||
fn bits2octets(x: &[u8], q: &UCN, qlen: usize) -> Vec<u8> {
|
||||
let z1 = bits2int(x, qlen);
|
||||
let res = if &z1 > q { z1 - q } else { z1 };
|
||||
int2octets(&res, qlen)
|
||||
}
|
||||
|
||||
fn int2octets(x: &UCN, qlen_bits: usize) -> Vec<u8> {
|
||||
let qlen_bytes = (qlen_bits + 7) / 8;
|
||||
x.to_bytes(qlen_bytes)
|
||||
}
|
||||
|
||||
fn runhmac<H>(base: &Hmac<H>, m: &[u8]) -> Vec<u8>
|
||||
where
|
||||
H: Clone + BlockInput + Input + FixedOutput + Default,
|
||||
Hmac<H>: Clone,
|
||||
H::BlockSize : ArrayLength<u8>
|
||||
{
|
||||
let mut runner = base.clone();
|
||||
runner.input(&m);
|
||||
runner.result().code().as_slice().to_vec()
|
||||
}
|
||||
|
||||
fn hmac<H>(k: &[u8], m: &[u8]) -> Vec<u8>
|
||||
where
|
||||
H: Clone + BlockInput + Input + FixedOutput + Default,
|
||||
Hmac<H>: Clone,
|
||||
H::BlockSize : ArrayLength<u8>
|
||||
{
|
||||
let mut runner = Hmac::<H>::new(&k).unwrap();
|
||||
runner.input(&m);
|
||||
runner.result().code().as_slice().to_vec()
|
||||
}
|
||||
|
||||
/// A DSA Signature
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct DSASignature {
|
||||
pub r: UCN,
|
||||
pub s: UCN
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub enum DSADecodeError {
|
||||
ASN1Error(ASN1DecodeErr),
|
||||
NoSignatureFound,
|
||||
NegativeSigValues
|
||||
}
|
||||
|
||||
impl From<ASN1DecodeErr> for DSADecodeError {
|
||||
fn from(a: ASN1DecodeErr) -> DSADecodeError {
|
||||
DSADecodeError::ASN1Error(a)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromASN1 for DSASignature {
|
||||
type Error = DSADecodeError;
|
||||
|
||||
fn from_asn1(v: &[ASN1Block])
|
||||
-> Result<(DSASignature,&[ASN1Block]),DSADecodeError>
|
||||
{
|
||||
match v.split_first() {
|
||||
Some((&ASN1Block::Sequence(_,_,ref info), rest))
|
||||
if info.len() == 2 =>
|
||||
{
|
||||
match (&info[0], &info[1]) {
|
||||
(&ASN1Block::Integer(_,_,ref rint),
|
||||
&ASN1Block::Integer(_,_,ref sint)) => {
|
||||
if rint.is_negative() || sint.is_negative() {
|
||||
return Err(DSADecodeError::NegativeSigValues)
|
||||
}
|
||||
let r = UCN::from(rint);
|
||||
let s = UCN::from(sint);
|
||||
Ok((DSASignature{ r: r, s: s }, rest))
|
||||
}
|
||||
_ => Err(DSADecodeError::NoSignatureFound)
|
||||
}
|
||||
}
|
||||
_ => Err(DSADecodeError::NoSignatureFound)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToASN1 for DSASignature {
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,ASN1EncodeErr>
|
||||
{
|
||||
let rb = ASN1Block::Integer(c, 0, BigInt::from(self.r.clone()));
|
||||
let sb = ASN1Block::Integer(c, 0, BigInt::from(self.s.clone()));
|
||||
Ok(vec![ASN1Block::Sequence(c, 0, vec![rb,sb])])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use sha2::Sha256;
|
||||
use super::*;
|
||||
|
||||
const QBYTES: [u8; 21] = [0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x02, 0x01, 0x08, 0xA2, 0xE0, 0xCC,
|
||||
0x0D, 0x99, 0xF8, 0xA5, 0xEF];
|
||||
const XBYTES: [u8; 21] = [0x00, 0x9A, 0x4D, 0x67, 0x92, 0x29, 0x5A, 0x7F,
|
||||
0x73, 0x0F, 0xC3, 0xF2, 0xB4, 0x9C, 0xBC, 0x0F,
|
||||
0x62, 0xE8, 0x62, 0x27, 0x2F];
|
||||
const H1: [u8; 32] = [0xAF, 0x2B, 0xDB, 0xE1, 0xAA, 0x9B, 0x6E, 0xC1,
|
||||
0xE2, 0xAD, 0xE1, 0xD6, 0x94, 0xF4, 0x1F, 0xC7,
|
||||
0x1A, 0x83, 0x1D, 0x02, 0x68, 0xE9, 0x89, 0x15,
|
||||
0x62, 0x11, 0x3D, 0x8A, 0x62, 0xAD, 0xD1, 0xBF];
|
||||
|
||||
#[test]
|
||||
fn int2octets_example() {
|
||||
let x = UCN::from_bytes(&XBYTES);
|
||||
let octets = int2octets(&x, 163);
|
||||
let target = vec![0x00, 0x9A, 0x4D, 0x67, 0x92, 0x29, 0x5A, 0x7F,
|
||||
0x73, 0x0F, 0xC3, 0xF2, 0xB4, 0x9C, 0xBC, 0x0F,
|
||||
0x62, 0xE8, 0x62, 0x27, 0x2F];
|
||||
assert_eq!(octets, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bits2octets_example() {
|
||||
let q = UCN::from_bytes(&QBYTES);
|
||||
let octets = bits2octets(&H1, &q, 163);
|
||||
let target = vec![0x01, 0x79, 0x5E, 0xDF, 0x0D, 0x54, 0xDB, 0x76,
|
||||
0x0F, 0x15, 0x6D, 0x0D, 0xAC, 0x04, 0xC0, 0x32,
|
||||
0x2B, 0x3A, 0x20, 0x42, 0x24];
|
||||
assert_eq!(octets, target);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn k_gen_example() {
|
||||
let q = UCN::from_bytes(&QBYTES);
|
||||
let x = UCN::from_bytes(&XBYTES);
|
||||
let mut iter = KIterator::<Sha256>::new(&H1, 163, &q, &x);
|
||||
match iter.next() {
|
||||
None =>
|
||||
assert!(false),
|
||||
Some(x) => {
|
||||
let target = vec![0x02, 0x3A, 0xF4, 0x07, 0x4C, 0x90, 0xA0,
|
||||
0x2B, 0x3F, 0xE6, 0x1D, 0x28, 0x6D, 0x5C,
|
||||
0x87, 0xF4, 0x25, 0xE6, 0xBD, 0xD8, 0x1B];
|
||||
let x2 = UCN::from_bytes(&target);
|
||||
assert_eq!(x, x2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,443 +0,0 @@
|
||||
use cryptonum::{BarrettUCN,SCN,UCN};
|
||||
use ecdsa::point::ECPoint;
|
||||
use std::fmt;
|
||||
|
||||
pub struct EllipticCurve {
|
||||
pub name: &'static str,
|
||||
pub p: [u8; 66],
|
||||
pub n: [u8; 66],
|
||||
pub seed: [u8; 66],
|
||||
pub c: [u8; 66],
|
||||
pub a: [u8; 66],
|
||||
pub b: [u8; 66],
|
||||
pub gx: [u8; 66],
|
||||
pub gy: [u8; 66]
|
||||
}
|
||||
|
||||
impl fmt::Debug for EllipticCurve {
|
||||
fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.name)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for EllipticCurve {
|
||||
fn eq(&self, other: &EllipticCurve) -> bool {
|
||||
self.name == other.name
|
||||
}
|
||||
}
|
||||
|
||||
impl EllipticCurve {
|
||||
pub fn get_p(&self) -> UCN {
|
||||
UCN::from_bytes(&self.p)
|
||||
}
|
||||
|
||||
pub fn get_pu(&self) -> BarrettUCN {
|
||||
self.get_p().barrett_uk(self.get_p().contents.len() + 4)
|
||||
}
|
||||
|
||||
pub fn get_n(&self) -> UCN {
|
||||
UCN::from_bytes(&self.n)
|
||||
}
|
||||
|
||||
pub fn get_seed(&self) -> UCN {
|
||||
UCN::from_bytes(&self.seed)
|
||||
}
|
||||
|
||||
pub fn get_c(&self) -> UCN {
|
||||
UCN::from_bytes(&self.c)
|
||||
}
|
||||
|
||||
pub fn get_a(&self) -> UCN {
|
||||
UCN::from_bytes(&self.a)
|
||||
}
|
||||
|
||||
pub fn get_b(&self) -> UCN {
|
||||
UCN::from_bytes(&self.b)
|
||||
}
|
||||
|
||||
pub fn default(&'static self) -> ECPoint {
|
||||
let x = SCN::from(UCN::from_bytes(&self.gx));
|
||||
let y = SCN::from(UCN::from_bytes(&self.gy));
|
||||
ECPoint::new(self, x, y)
|
||||
}
|
||||
}
|
||||
|
||||
pub const NIST_P192: EllipticCurve = EllipticCurve {
|
||||
name: "secp192r1",
|
||||
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff ],
|
||||
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0xde,
|
||||
0xf8, 0x36, 0x14, 0x6b, 0xc9, 0xb1, 0xb4, 0xd2,
|
||||
0x28, 0x31 ],
|
||||
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x45,
|
||||
0xae, 0x6f, 0xc8, 0x42, 0x2f, 0x64, 0xed, 0x57,
|
||||
0x95, 0x28, 0xd3, 0x81, 0x20, 0xea, 0xe1, 0x21,
|
||||
0x96, 0xd5 ],
|
||||
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x30, 0x99, 0xd2, 0xbb, 0xbf, 0xcb,
|
||||
0x25, 0x38, 0x54, 0x2d, 0xcd, 0x5f, 0xb0, 0x78,
|
||||
0xb6, 0xef, 0x5f, 0x3d, 0x6f, 0xe2, 0xc7, 0x45,
|
||||
0xde, 0x65 ],
|
||||
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc ],
|
||||
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x64, 0x21, 0x05, 0x19, 0xe5, 0x9c,
|
||||
0x80, 0xe7, 0x0f, 0xa7, 0xe9, 0xab, 0x72, 0x24,
|
||||
0x30, 0x49, 0xfe, 0xb8, 0xde, 0xec, 0xc1, 0x46,
|
||||
0xb9, 0xb1 ],
|
||||
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0x8d, 0xa8, 0x0e, 0xb0, 0x30,
|
||||
0x90, 0xf6, 0x7c, 0xbf, 0x20, 0xeb, 0x43, 0xa1,
|
||||
0x88, 0x00, 0xf4, 0xff, 0x0a, 0xfd, 0x82, 0xff,
|
||||
0x10, 0x12 ],
|
||||
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x07, 0x19, 0x2b, 0x95, 0xff, 0xc8,
|
||||
0xda, 0x78, 0x63, 0x10, 0x11, 0xed, 0x6b, 0x24,
|
||||
0xcd, 0xd5, 0x73, 0xf9, 0x77, 0xa1, 0x1e, 0x79,
|
||||
0x48, 0x11 ]
|
||||
};
|
||||
|
||||
pub const NIST_P224: EllipticCurve = EllipticCurve {
|
||||
name: "secp224r1",
|
||||
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01],
|
||||
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, 0xe0, 0xb8,
|
||||
0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, 0x5c, 0x5c,
|
||||
0x2a, 0x3d],
|
||||
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x71,
|
||||
0x34, 0x47, 0x99, 0xd5, 0xc7, 0xfc, 0xdc, 0x45,
|
||||
0xb5, 0x9f, 0xa3, 0xb9, 0xab, 0x8f, 0x6a, 0x94,
|
||||
0x8b, 0xc5],
|
||||
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x05,
|
||||
0x6c, 0x7e, 0x11, 0xdd, 0x68, 0xf4, 0x04, 0x69,
|
||||
0xee, 0x7f, 0x3c, 0x7a, 0x7d, 0x74, 0xf7, 0xd1,
|
||||
0x21, 0x11, 0x65, 0x06, 0xd0, 0x31, 0x21, 0x82,
|
||||
0x91, 0xfb],
|
||||
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe],
|
||||
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0x05,
|
||||
0x0a, 0x85, 0x0c, 0x04, 0xb3, 0xab, 0xf5, 0x41,
|
||||
0x32, 0x56, 0x50, 0x44, 0xb0, 0xb7, 0xd7, 0xbf,
|
||||
0xd8, 0xba, 0x27, 0x0b, 0x39, 0x43, 0x23, 0x55,
|
||||
0xff, 0xb4],
|
||||
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x0e,
|
||||
0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13,
|
||||
0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, 0x56, 0xc2,
|
||||
0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, 0x11, 0x5c,
|
||||
0x1d, 0x21],
|
||||
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x37,
|
||||
0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22,
|
||||
0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07,
|
||||
0x47, 0x64, 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00,
|
||||
0x7e, 0x34]
|
||||
};
|
||||
|
||||
pub const NIST_P256: EllipticCurve = EllipticCurve {
|
||||
name: "secp256r1",
|
||||
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff],
|
||||
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
|
||||
0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63,
|
||||
0x25, 0x51],
|
||||
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x9d,
|
||||
0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66,
|
||||
0x78, 0xe1, 0x13, 0x9d, 0x26, 0xb7, 0x81, 0x9f,
|
||||
0x7e, 0x90],
|
||||
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x7e, 0xfb, 0xa1, 0x66, 0x29, 0x85,
|
||||
0xbe, 0x94, 0x03, 0xcb, 0x05, 0x5c, 0x75, 0xd4,
|
||||
0xf7, 0xe0, 0xce, 0x8d, 0x84, 0xa9, 0xc5, 0x11,
|
||||
0x4a, 0xbc, 0xaf, 0x31, 0x77, 0x68, 0x01, 0x04,
|
||||
0xfa, 0x0d],
|
||||
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc],
|
||||
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a,
|
||||
0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98,
|
||||
0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
|
||||
0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2,
|
||||
0x60, 0x4b],
|
||||
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c,
|
||||
0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4,
|
||||
0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb,
|
||||
0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98,
|
||||
0xc2, 0x96],
|
||||
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a,
|
||||
0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f,
|
||||
0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31,
|
||||
0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf,
|
||||
0x51, 0xf5]
|
||||
};
|
||||
|
||||
pub const NIST_P384: EllipticCurve = EllipticCurve {
|
||||
name: "secp384r1",
|
||||
p: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xff],
|
||||
n: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37,
|
||||
0x2d, 0xdf, 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0,
|
||||
0xa7, 0x7a, 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5,
|
||||
0x29, 0x73],
|
||||
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x35,
|
||||
0x92, 0x6a, 0xa3, 0x19, 0xa2, 0x7a, 0x1d, 0x00,
|
||||
0x89, 0x6a, 0x67, 0x73, 0xa4, 0x82, 0x7a, 0xcd,
|
||||
0xac, 0x73],
|
||||
c: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x79, 0xd1, 0xe6, 0x55, 0xf8, 0x68,
|
||||
0xf0, 0x2f, 0xff, 0x48, 0xdc, 0xde, 0xe1, 0x41,
|
||||
0x51, 0xdd, 0xb8, 0x06, 0x43, 0xc1, 0x40, 0x6d,
|
||||
0x0c, 0xa1, 0x0d, 0xfe, 0x6f, 0xc5, 0x20, 0x09,
|
||||
0x54, 0x0a, 0x49, 0x5e, 0x80, 0x42, 0xea, 0x5f,
|
||||
0x74, 0x4f, 0x6e, 0x18, 0x46, 0x67, 0xcc, 0x72,
|
||||
0x24, 0x83],
|
||||
a: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0xff, 0xfc],
|
||||
b: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e,
|
||||
0xe7, 0xe4, 0x98, 0x8e, 0x05, 0x6b, 0xe3, 0xf8,
|
||||
0x2d, 0x19, 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81,
|
||||
0x41, 0x12, 0x03, 0x14, 0x08, 0x8f, 0x50, 0x13,
|
||||
0x87, 0x5a, 0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e,
|
||||
0xd1, 0x9d, 0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec,
|
||||
0x2a, 0xef],
|
||||
gx: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b,
|
||||
0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20,
|
||||
0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7,
|
||||
0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54,
|
||||
0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55,
|
||||
0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76,
|
||||
0x0a, 0xb7],
|
||||
gy: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26,
|
||||
0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92,
|
||||
0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a,
|
||||
0x14, 0x7c, 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0,
|
||||
0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e,
|
||||
0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea,
|
||||
0x0e, 0x5f]
|
||||
};
|
||||
|
||||
pub const NIST_P521: EllipticCurve = EllipticCurve {
|
||||
name: "secp521r1",
|
||||
p: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff ],
|
||||
n: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f,
|
||||
0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09,
|
||||
0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c,
|
||||
0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38,
|
||||
0x64, 0x09 ],
|
||||
seed: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x9e,
|
||||
0x88, 0x00, 0x29, 0x1c, 0xb8, 0x53, 0x96, 0xcc,
|
||||
0x67, 0x17, 0x39, 0x32, 0x84, 0xaa, 0xa0, 0xda,
|
||||
0x64, 0xba ],
|
||||
c: [ 0x00, 0xb4, 0x8b, 0xfa, 0x5f, 0x42, 0x0a, 0x34,
|
||||
0x94, 0x95, 0x39, 0xd2, 0xbd, 0xfc, 0x26, 0x4e,
|
||||
0xee, 0xeb, 0x07, 0x76, 0x88, 0xe4, 0x4f, 0xbf,
|
||||
0x0a, 0xd8, 0xf6, 0xd0, 0xed, 0xb3, 0x7b, 0xd6,
|
||||
0xb5, 0x33, 0x28, 0x10, 0x00, 0x51, 0x8e, 0x19,
|
||||
0xf1, 0xb9, 0xff, 0xbe, 0x0f, 0xe9, 0xed, 0x8a,
|
||||
0x3c, 0x22, 0x00, 0xb8, 0xf8, 0x75, 0xe5, 0x23,
|
||||
0x86, 0x8c, 0x70, 0xc1, 0xe5, 0xbf, 0x55, 0xba,
|
||||
0xd6, 0x37 ],
|
||||
a: [ 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfc ],
|
||||
b: [ 0x00, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c,
|
||||
0x9a, 0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85,
|
||||
0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3,
|
||||
0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1,
|
||||
0x09, 0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e,
|
||||
0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1,
|
||||
0xbf, 0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c,
|
||||
0x34, 0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50,
|
||||
0x3f, 0x00 ],
|
||||
gx: [ 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04,
|
||||
0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95,
|
||||
0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f,
|
||||
0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d,
|
||||
0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7,
|
||||
0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff,
|
||||
0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a,
|
||||
0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5,
|
||||
0xbd, 0x66 ],
|
||||
gy: [ 0x00, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b,
|
||||
0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d,
|
||||
0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b,
|
||||
0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e,
|
||||
0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4,
|
||||
0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad,
|
||||
0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72,
|
||||
0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1,
|
||||
0x66, 0x50 ]
|
||||
};
|
||||
@@ -1,187 +0,0 @@
|
||||
use cryptonum::{SCN,UCN};
|
||||
//use dsa::rfc6979::*;
|
||||
use ecdsa::curves::*;
|
||||
use ecdsa::point::ECPoint;
|
||||
//use ecdsa::private::ECDSAPrivate;
|
||||
//use ecdsa::public::ECDSAPublic;
|
||||
//use sha1::Sha1;
|
||||
//use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||
use testing::run_test;
|
||||
|
||||
fn get_curve(cbytes: &[u8]) -> &'static EllipticCurve {
|
||||
match usize::from(UCN::from_bytes(cbytes)) {
|
||||
0x192 => &NIST_P192,
|
||||
0x224 => &NIST_P224,
|
||||
0x256 => &NIST_P256,
|
||||
0x384 => &NIST_P384,
|
||||
0x521 => &NIST_P521,
|
||||
x => panic!("Unacceptable curve identifier {}", x)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn point_negate()
|
||||
{
|
||||
run_test("tests/ecdsa/ec_negate.test", 5, |case| {
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, bbytes) = case.get("b").unwrap();
|
||||
let (neg2, cbytes) = case.get("c").unwrap();
|
||||
let (neg3, xbytes) = case.get("x").unwrap();
|
||||
let (neg4, ybytes) = case.get("y").unwrap();
|
||||
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
|
||||
let curve = get_curve(&cbytes);
|
||||
let x = SCN::from(UCN::from_bytes(xbytes));
|
||||
let y = SCN::from(UCN::from_bytes(ybytes));
|
||||
let orig = ECPoint::new(curve, x, y);
|
||||
let a = SCN::from(UCN::from_bytes(abytes));
|
||||
let b = SCN::from(UCN::from_bytes(bbytes));
|
||||
let inverted = ECPoint::new(curve, a, b);
|
||||
assert_eq!(inverted, orig.negate());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn point_double()
|
||||
{
|
||||
run_test("tests/ecdsa/ec_dble.test", 5, |case| {
|
||||
println!("START");
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, bbytes) = case.get("b").unwrap();
|
||||
let (neg2, cbytes) = case.get("c").unwrap();
|
||||
let (neg3, xbytes) = case.get("x").unwrap();
|
||||
let (neg4, ybytes) = case.get("y").unwrap();
|
||||
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4);
|
||||
println!("SEC1");
|
||||
let curve = get_curve(&cbytes);
|
||||
println!("SEC2");
|
||||
let x = SCN::from(UCN::from_bytes(xbytes));
|
||||
let y = SCN::from(UCN::from_bytes(ybytes));
|
||||
let orig = ECPoint::new(curve, x, y);
|
||||
println!("SEC3");
|
||||
let a = SCN::from(UCN::from_bytes(abytes));
|
||||
let b = SCN::from(UCN::from_bytes(bbytes));
|
||||
let doubled = ECPoint::new(curve, a, b);
|
||||
println!("SEC4");
|
||||
assert_eq!(doubled, orig.double());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn point_add()
|
||||
{
|
||||
run_test("tests/ecdsa/ec_add.test", 7, |case| {
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, bbytes) = case.get("b").unwrap();
|
||||
let (neg2, qbytes) = case.get("q").unwrap();
|
||||
let (neg3, rbytes) = case.get("r").unwrap();
|
||||
let (neg4, cbytes) = case.get("c").unwrap();
|
||||
let (neg5, xbytes) = case.get("x").unwrap();
|
||||
let (neg6, ybytes) = case.get("y").unwrap();
|
||||
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5 && !neg6);
|
||||
let curve = get_curve(&cbytes);
|
||||
let x = SCN::from(UCN::from_bytes(xbytes));
|
||||
let y = SCN::from(UCN::from_bytes(ybytes));
|
||||
let p1 = ECPoint::new(curve, x, y);
|
||||
let q = SCN::from(UCN::from_bytes(qbytes));
|
||||
let r = SCN::from(UCN::from_bytes(rbytes));
|
||||
let p2 = ECPoint::new(curve, q, r);
|
||||
let a = SCN::from(UCN::from_bytes(abytes));
|
||||
let b = SCN::from(UCN::from_bytes(bbytes));
|
||||
let result = ECPoint::new(curve, a, b);
|
||||
assert_eq!(result, p1.add(&p2));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn point_scale()
|
||||
{
|
||||
run_test("tests/ecdsa/ec_mul.test", 6, |case| {
|
||||
let (neg0, abytes) = case.get("a").unwrap();
|
||||
let (neg1, bbytes) = case.get("b").unwrap();
|
||||
let (neg2, kbytes) = case.get("k").unwrap();
|
||||
let (neg3, cbytes) = case.get("c").unwrap();
|
||||
let (neg4, xbytes) = case.get("x").unwrap();
|
||||
let (neg5, ybytes) = case.get("y").unwrap();
|
||||
|
||||
assert!(!neg0 && !neg1 && !neg2 && !neg3 && !neg4 && !neg5);
|
||||
let curve = get_curve(&cbytes);
|
||||
let x = SCN::from(UCN::from_bytes(xbytes));
|
||||
let y = SCN::from(UCN::from_bytes(ybytes));
|
||||
let base = ECPoint::new(curve, x, y);
|
||||
let k = UCN::from_bytes(kbytes);
|
||||
let a = SCN::from(UCN::from_bytes(abytes));
|
||||
let b = SCN::from(UCN::from_bytes(bbytes));
|
||||
let result = ECPoint::new(curve, a, b);
|
||||
assert_eq!(result, base.scale(&k));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//#[test]
|
||||
//fn verification_tests()
|
||||
//{
|
||||
// run_test("tests/ecdsa/signature.test", 8, |case| {
|
||||
// let (neg0, cbytes) = case.get("c").unwrap();
|
||||
// let (negx, xbytes) = case.get("x").unwrap();
|
||||
// let (negy, ybytes) = case.get("y").unwrap();
|
||||
// let (neg1, hbytes) = case.get("h").unwrap();
|
||||
// let (neg2, msg) = case.get("m").unwrap();
|
||||
// let (neg3, rbytes) = case.get("r").unwrap();
|
||||
// let (neg4, sbytes) = case.get("s").unwrap();
|
||||
//
|
||||
// assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4);
|
||||
// let curve = get_curve(cbytes);
|
||||
// let ux = UCN::from_bytes(xbytes);
|
||||
// let uy = UCN::from_bytes(ybytes);
|
||||
// let x = SCN{ negative: *negx, value: ux };
|
||||
// let y = SCN{ negative: *negy, value: uy };
|
||||
// let point = ECCPoint::new(&curve, x, y);
|
||||
// let public = ECDSAPublic::new(&curve, &point);
|
||||
// let r = UCN::from_bytes(rbytes);
|
||||
// let s = UCN::from_bytes(sbytes);
|
||||
// println!("r: {:X}", r);
|
||||
// let sig = DSASignature{ r: r, s: s };
|
||||
//
|
||||
// match usize::from(UCN::from_bytes(hbytes)) {
|
||||
// 0x1 => assert!(public.verify::<Sha1>(msg, &sig)),
|
||||
// 0x224 => assert!(public.verify::<Sha224>(msg, &sig)),
|
||||
// 0x256 => assert!(public.verify::<Sha256>(msg, &sig)),
|
||||
// 0x384 => assert!(public.verify::<Sha384>(msg, &sig)),
|
||||
// 0x512 => assert!(public.verify::<Sha512>(msg, &sig)),
|
||||
// v => panic!("Bad hash size {}!", v)
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
//
|
||||
//#[test]
|
||||
//fn signing_tests()
|
||||
//{
|
||||
// run_test("tests/ecdsa/signature.test", 8, |case| {
|
||||
// let (neg0, cbytes) = case.get("c").unwrap();
|
||||
// let (neg1, dbytes) = case.get("d").unwrap();
|
||||
// let (neg2, hbytes) = case.get("h").unwrap();
|
||||
// let (neg3, msg) = case.get("m").unwrap();
|
||||
// let (neg4, rbytes) = case.get("r").unwrap();
|
||||
// let (neg5, sbytes) = case.get("s").unwrap();
|
||||
//
|
||||
// assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5);
|
||||
// let curve = get_curve(cbytes);
|
||||
// let d = UCN::from_bytes(dbytes);
|
||||
// let private = ECDSAPrivate::new(&curve, &d);
|
||||
// let r = UCN::from_bytes(rbytes);
|
||||
// let s = UCN::from_bytes(sbytes);
|
||||
// let sig = DSASignature{ r: r, s: s };
|
||||
//
|
||||
// match usize::from(UCN::from_bytes(hbytes)) {
|
||||
// 0x1 => assert_eq!(sig, private.sign::<Sha1>(msg)),
|
||||
// 0x224 => assert_eq!(sig, private.sign::<Sha224>(msg)),
|
||||
// 0x256 => assert_eq!(sig, private.sign::<Sha256>(msg)),
|
||||
// 0x384 => assert_eq!(sig, private.sign::<Sha384>(msg)),
|
||||
// 0x512 => assert_eq!(sig, private.sign::<Sha512>(msg)),
|
||||
// v => panic!("Bad hash size {}!", v)
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
@@ -1,61 +0,0 @@
|
||||
mod curves;
|
||||
#[cfg(test)]
|
||||
mod gold_tests;
|
||||
mod point;
|
||||
//mod private;
|
||||
//mod public;
|
||||
//
|
||||
//pub use self::private::ECDSAPrivate;
|
||||
//pub use self::public::ECDSAPublic;
|
||||
pub use self::curves::{NIST_P192,NIST_P224,NIST_P256,NIST_P384,NIST_P521};
|
||||
//
|
||||
//use cryptonum::UCN;
|
||||
//use rand::{Rng,OsRng};
|
||||
//use self::curves::EllipticCurve;
|
||||
//use self::math::ECCPoint;
|
||||
//
|
||||
//#[derive(Clone,Debug,PartialEq)]
|
||||
//pub struct ECDSAKeyPair {
|
||||
// pub private: ECDSAPrivate,
|
||||
// pub public: ECDSAPublic
|
||||
//}
|
||||
//
|
||||
//impl ECDSAKeyPair {
|
||||
// pub fn generate(params: &'static EllipticCurve)
|
||||
// -> ECDSAKeyPair
|
||||
// {
|
||||
// let mut rng = OsRng::new().unwrap();
|
||||
// ECDSAKeyPair::generate_w_rng(&mut rng, params)
|
||||
//
|
||||
// }
|
||||
//
|
||||
// pub fn generate_w_rng<G: Rng>(rng: &mut G, params: &'static EllipticCurve)
|
||||
// -> ECDSAKeyPair
|
||||
// {
|
||||
// let one = UCN::from(1u64);
|
||||
// #[allow(non_snake_case)]
|
||||
// let N = params.n.bits();
|
||||
// let bits_to_generate = N + 64;
|
||||
// let bytes_to_generate = (bits_to_generate + 7) / 8;
|
||||
// let bits: Vec<u8> = rng.gen_iter().take(bytes_to_generate).collect();
|
||||
// let bits_generated = bytes_to_generate * 8;
|
||||
// let mut c = UCN::from_bytes(&bits);
|
||||
// c >>= bits_generated - bits_to_generate;
|
||||
// let nm1 = ¶ms.n - &one;
|
||||
// let d = (c % &nm1) + &one;
|
||||
// #[allow(non_snake_case)]
|
||||
// let Q = ECCPoint::default(params).scale(&d);
|
||||
// ECDSAKeyPair {
|
||||
// private: ECDSAPrivate {
|
||||
// curve: params,
|
||||
// d: d
|
||||
// },
|
||||
// public: ECDSAPublic {
|
||||
// curve: params,
|
||||
// Q: Q
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
@@ -1,227 +0,0 @@
|
||||
use cryptonum::{SCN,UCN};
|
||||
use ecdsa::curves::EllipticCurve;
|
||||
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct ECPoint {
|
||||
pub curve: &'static EllipticCurve,
|
||||
pub value: ECPointValue
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub enum ECPointValue {
|
||||
Infinity,
|
||||
Point(SCN, SCN)
|
||||
}
|
||||
|
||||
impl ECPoint {
|
||||
pub fn new(ec: &'static EllipticCurve, x: SCN, y: SCN) -> ECPoint {
|
||||
ECPoint {
|
||||
curve: ec,
|
||||
value: ECPointValue::Point(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zero(ec: &'static EllipticCurve) -> ECPoint {
|
||||
ECPoint { curve: ec, value: ECPointValue::Infinity }
|
||||
}
|
||||
|
||||
pub fn negate(&self) -> ECPoint {
|
||||
match self.value {
|
||||
ECPointValue::Infinity =>
|
||||
self.clone(),
|
||||
ECPointValue::Point(ref x, ref y) => {
|
||||
let newy = SCN::from(self.curve.get_p()) - y;
|
||||
let newv = ECPointValue::Point(x.clone(), newy);
|
||||
ECPoint{ curve: self.curve, value: newv }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_x(&self) -> SCN {
|
||||
match self.value {
|
||||
ECPointValue::Infinity =>
|
||||
SCN::zero(),
|
||||
ECPointValue::Point(ref x, _) =>
|
||||
x.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_y(&self) -> SCN {
|
||||
match self.value {
|
||||
ECPointValue::Infinity =>
|
||||
SCN::zero(),
|
||||
ECPointValue::Point(_, ref y) =>
|
||||
y.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn double(&self) -> ECPoint {
|
||||
match self.value {
|
||||
ECPointValue::Infinity =>
|
||||
self.clone(),
|
||||
ECPointValue::Point(ref x, ref y) => {
|
||||
let ua = SCN::from(self.curve.get_a());
|
||||
let up = SCN::from(self.curve.get_p());
|
||||
// lambda = (3 * xp ^ 2 + a) / 2 yp
|
||||
let mut lambda = x * x;
|
||||
lambda *= SCN::from(3);
|
||||
lambda += &ua;
|
||||
let twoy = y << 1;
|
||||
lambda = lambda.divmod(&twoy, &self.curve.get_pu());
|
||||
// xr = lambda ^ 2 - 2 xp
|
||||
let mut xr = &lambda * λ
|
||||
let xr_right = x << 1;
|
||||
xr -= xr_right;
|
||||
assert!(!xr.is_negative());
|
||||
xr %= &up;
|
||||
// yr = lambda (xp - xr) - yp
|
||||
let xdiff = x - &xr;
|
||||
let mut yr = &lambda * &xdiff;
|
||||
yr -= y;
|
||||
assert!(!yr.is_negative());
|
||||
yr %= up;
|
||||
//
|
||||
ECPoint {
|
||||
curve: self.curve,
|
||||
value: ECPointValue::Point(xr, yr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&self, other: &ECPoint) -> ECPoint {
|
||||
assert_eq!(self.curve, other.curve);
|
||||
match (&self.value, &other.value) {
|
||||
(ECPointValue::Infinity, ECPointValue::Infinity) =>
|
||||
self.clone(),
|
||||
(ECPointValue::Infinity, _) =>
|
||||
other.clone(),
|
||||
(_, ECPointValue::Infinity) =>
|
||||
self.clone(),
|
||||
(ECPointValue::Point(ref sx, ref sy),
|
||||
ECPointValue::Point(ref ox, ref oy)) => {
|
||||
let xdiff = sx - ox;
|
||||
let ydiff = sy - oy;
|
||||
let pu = self.curve.get_pu();
|
||||
let s = ydiff.divmod(&xdiff, &pu);
|
||||
let mut xr = &s * &s;
|
||||
xr -= sx;
|
||||
xr -= ox;
|
||||
xr = xr.reduce(&pu);
|
||||
let mut yr = sx - &xr;
|
||||
yr *= &s;
|
||||
yr -= sy;
|
||||
yr = yr.reduce(&pu);
|
||||
let val = ECPointValue::Point(xr, yr);
|
||||
ECPoint{ curve: self.curve, value: val }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scale(&self, d: &UCN) -> ECPoint {
|
||||
match self.value {
|
||||
ECPointValue::Infinity =>
|
||||
self.clone(),
|
||||
ECPointValue::Point(_, _) => {
|
||||
if d.is_zero() {
|
||||
return ECPoint::zero(self.curve);
|
||||
}
|
||||
|
||||
let mut q = self.clone();
|
||||
let i = d.bits() - 2;
|
||||
let mut mask = UCN::from(1u64) << i;
|
||||
|
||||
while !mask.is_zero() {
|
||||
q = q.double();
|
||||
|
||||
let test = d & &mask;
|
||||
if !test.is_zero() {
|
||||
q = q.add(&self);
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
q
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// pub fn bits2int(x: &[u8], qlen: usize) -> UCN {
|
||||
// let mut value = UCN::from_bytes(x);
|
||||
// let vlen = x.len() * 8;
|
||||
//
|
||||
// if vlen > qlen {
|
||||
// value >>= vlen - qlen;
|
||||
// }
|
||||
//
|
||||
// value
|
||||
// }
|
||||
//
|
||||
// pub fn point_add_two_muls(k1: &UCN, p1: &ECCPoint, k2: &UCN, p2: &ECCPoint)
|
||||
// -> ECCPoint
|
||||
// {
|
||||
// panic!("point_add_two_muls()")
|
||||
// }
|
||||
//
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
//
|
||||
// #[test]
|
||||
// fn p256_double() {
|
||||
// let xbytes = vec![0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e,
|
||||
// 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3,
|
||||
// 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35,
|
||||
// 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78];
|
||||
// let ybytes = vec![0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40,
|
||||
// 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb,
|
||||
// 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29,
|
||||
// 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1];
|
||||
// let x = SCN::from(UCN::from_bytes(&xbytes));
|
||||
// let y = SCN::from(UCN::from_bytes(&ybytes));
|
||||
// let base = ECCPoint::default(&EllipticCurve::p256());
|
||||
// let res = base.double();
|
||||
// let goal = ECCPoint{ curve: base.curve,
|
||||
// value: ECCPointValue::Point(x,y) };
|
||||
// assert_eq!(res, goal);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn p256_add() {
|
||||
// let xbytes = vec![0x5e, 0xcb, 0xe4, 0xd1, 0xa6, 0x33, 0x0a, 0x44,
|
||||
// 0xc8, 0xf7, 0xef, 0x95, 0x1d, 0x4b, 0xf1, 0x65,
|
||||
// 0xe6, 0xc6, 0xb7, 0x21, 0xef, 0xad, 0xa9, 0x85,
|
||||
// 0xfb, 0x41, 0x66, 0x1b, 0xc6, 0xe7, 0xfd, 0x6c];
|
||||
// let ybytes = vec![0x87, 0x34, 0x64, 0x0c, 0x49, 0x98, 0xff, 0x7e,
|
||||
// 0x37, 0x4b, 0x06, 0xce, 0x1a, 0x64, 0xa2, 0xec,
|
||||
// 0xd8, 0x2a, 0xb0, 0x36, 0x38, 0x4f, 0xb8, 0x3d,
|
||||
// 0x9a, 0x79, 0xb1, 0x27, 0xa2, 0x7d, 0x50, 0x32];
|
||||
// let x = SCN::from(UCN::from_bytes(&xbytes));
|
||||
// let y = SCN::from(UCN::from_bytes(&ybytes));
|
||||
// let base = ECCPoint::default(&EllipticCurve::p256());
|
||||
// let res = base.add(&base.double());
|
||||
// let goal = ECCPoint{ curve: base.curve,
|
||||
// value: ECCPointValue::Point(x,y) };
|
||||
// assert_eq!(res, goal);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn p256_scale() {
|
||||
// let xbytes = vec![0xea, 0x68, 0xd7, 0xb6, 0xfe, 0xdf, 0x0b, 0x71,
|
||||
// 0x87, 0x89, 0x38, 0xd5, 0x1d, 0x71, 0xf8, 0x72,
|
||||
// 0x9e, 0x0a, 0xcb, 0x8c, 0x2c, 0x6d, 0xf8, 0xb3,
|
||||
// 0xd7, 0x9e, 0x8a, 0x4b, 0x90, 0x94, 0x9e, 0xe0];
|
||||
// let ybytes = vec![0x2a, 0x27, 0x44, 0xc9, 0x72, 0xc9, 0xfc, 0xe7,
|
||||
// 0x87, 0x01, 0x4a, 0x96, 0x4a, 0x8e, 0xa0, 0xc8,
|
||||
// 0x4d, 0x71, 0x4f, 0xea, 0xa4, 0xde, 0x82, 0x3f,
|
||||
// 0xe8, 0x5a, 0x22, 0x4a, 0x4d, 0xd0, 0x48, 0xfa];
|
||||
// let x = SCN::from(UCN::from_bytes(&xbytes));
|
||||
// let y = SCN::from(UCN::from_bytes(&ybytes));
|
||||
// let base = ECCPoint::default(&EllipticCurve::p256());
|
||||
// let res = base.scale(&UCN::from(9 as u64));
|
||||
// let goal = ECCPoint{ curve: base.curve,
|
||||
// value: ECCPointValue::Point(x,y) };
|
||||
// assert_eq!(res, goal);
|
||||
// }
|
||||
// }
|
||||
@@ -1,93 +0,0 @@
|
||||
use cryptonum::{SCN,UCN};
|
||||
use digest::{BlockInput,FixedOutput,Input};
|
||||
use digest::generic_array::ArrayLength;
|
||||
use dsa::rfc6979::{DSASignature,KIterator};
|
||||
use ecdsa::curves::EllipticCurve;
|
||||
use ecdsa::math::{ECCPoint,bits2int};
|
||||
use hmac::Hmac;
|
||||
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct ECDSAPrivate {
|
||||
pub(crate) curve: &'static EllipticCurve,
|
||||
pub(crate) d: UCN
|
||||
}
|
||||
|
||||
impl ECDSAPrivate {
|
||||
pub fn new(c: &'static EllipticCurve, d: &UCN)
|
||||
-> ECDSAPrivate
|
||||
{
|
||||
ECDSAPrivate {
|
||||
curve: c,
|
||||
d: d.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sign<Hash>(&self, m: &[u8]) -> DSASignature
|
||||
where
|
||||
Hash: Clone + BlockInput + Input + FixedOutput + Default,
|
||||
Hmac<Hash>: Clone,
|
||||
Hash::BlockSize: ArrayLength<u8>
|
||||
{
|
||||
// This algorithm is per RFC 6979, which has a nice, relatively
|
||||
// straightforward description of how to do DSA signing.
|
||||
//
|
||||
// 1. H(m) is transformed into an integer modulo q using the bits2int
|
||||
// transform and an extra modular reduction:
|
||||
//
|
||||
// h = bits2int(H(m)) mod q
|
||||
//
|
||||
// As was noted in the description of bits2octets, the extra
|
||||
// modular reduction is no more than a conditional subtraction.
|
||||
//
|
||||
let mut digest = <Hash>::default();
|
||||
digest.process(m);
|
||||
let n = self.curve.p.bits();
|
||||
let h1: Vec<u8> = digest.fixed_result()
|
||||
.as_slice()
|
||||
.iter()
|
||||
.map(|x| *x)
|
||||
.collect();
|
||||
let h0 = bits2int(&h1, n);
|
||||
let h = h0 % &self.curve.n;
|
||||
|
||||
// 2. A random value modulo q, dubbed k, is generated. That value
|
||||
// shall not be 0; hence, it lies in the [1, q-1] range. Most
|
||||
// of the remainder of this document will revolve around the
|
||||
// process used to generate k. In plain DSA or ECDSA, k should
|
||||
// be selected through a random selection that chooses a value
|
||||
// among the q-1 possible values with uniform probability.
|
||||
for k in KIterator::<Hash>::new(&h1, n, &self.curve.n, &self.curve.b) {
|
||||
// 3. A value r (modulo q) is computed from k and the key
|
||||
// parameters:
|
||||
// * For DSA ...
|
||||
// * For ECDSA: the point kG is computed; its X coordinate (a
|
||||
// member of the field over which E is defined) is converted
|
||||
// to an integer, which is reduced modulo q, yielding r.
|
||||
//
|
||||
// If r turns out to be zero, a new k should be selected and r
|
||||
// computed again (this is an utterly improbable occurrence).
|
||||
let g = ECCPoint::default(self.curve);
|
||||
let kg = g.scale(&k);
|
||||
let ni = SCN::from(self.curve.n.clone());
|
||||
let r = &kg.get_x() % ∋
|
||||
if r.is_zero() {
|
||||
continue;
|
||||
}
|
||||
// 4. The value s (modulo q) is computed:
|
||||
//
|
||||
// s = (h+x*r)/k mod q
|
||||
//
|
||||
// The pair (r, s) is the signature.
|
||||
let kinv = SCN::from(k.modinv(&ni.value));
|
||||
let s = ((SCN::from(h.clone()) + (&kg.get_x() * &r)) * &kinv) % ∋
|
||||
if s.is_zero() {
|
||||
continue;
|
||||
}
|
||||
|
||||
assert!(!r.is_negative());
|
||||
assert!(!s.is_negative());
|
||||
return DSASignature{ r: r.value, s: s.value };
|
||||
}
|
||||
panic!("The world is broken; couldn't find a k in sign().");
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
use digest::{BlockInput,FixedOutput,Input};
|
||||
use digest::generic_array::ArrayLength;
|
||||
use dsa::rfc6979::DSASignature;
|
||||
use ecdsa::curves::EllipticCurve;
|
||||
use ecdsa::math::{ECCPoint,bits2int,point_add_two_muls};
|
||||
use hmac::Hmac;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct ECDSAPublic {
|
||||
pub(crate) curve: &'static EllipticCurve,
|
||||
pub(crate) Q: ECCPoint
|
||||
}
|
||||
|
||||
impl ECDSAPublic {
|
||||
pub fn new(curve: &'static EllipticCurve, point: &ECCPoint)
|
||||
-> ECDSAPublic
|
||||
{
|
||||
ECDSAPublic {
|
||||
curve: curve,
|
||||
Q: point.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify<Hash>(&self, m: &[u8], sig: &DSASignature) -> bool
|
||||
where
|
||||
Hash: Clone + BlockInput + Input + FixedOutput + Default,
|
||||
Hmac<Hash>: Clone,
|
||||
Hash::BlockSize: ArrayLength<u8>
|
||||
{
|
||||
let n = &self.curve.n;
|
||||
|
||||
if &sig.r > n {
|
||||
return false;
|
||||
}
|
||||
if &sig.s > n {
|
||||
return false;
|
||||
}
|
||||
|
||||
let c = sig.s.modinv(&n);
|
||||
|
||||
let mut digest = <Hash>::default();
|
||||
digest.process(m);
|
||||
let h1: Vec<u8> = digest.fixed_result()
|
||||
.as_slice()
|
||||
.iter()
|
||||
.map(|x| *x)
|
||||
.collect();
|
||||
let h0 = bits2int(&h1, self.curve.p.bits()) % n;
|
||||
let u1 = (&h0 * &c) % n;
|
||||
let u2 = (&sig.r * &c) % n;
|
||||
let x = point_add_two_muls(&u1, &ECCPoint::default(&self.curve),
|
||||
&u2, &self.Q);
|
||||
let xx = x.get_x();
|
||||
|
||||
if xx.is_negative() {
|
||||
return false;
|
||||
}
|
||||
|
||||
(xx.value % n) == sig.r
|
||||
}
|
||||
}
|
||||
30
src/lib.rs
30
src/lib.rs
@@ -1,3 +1,4 @@
|
||||
#![feature(i128_type)]
|
||||
//! # Simple Crypto: A quaint little crypto library for rust.
|
||||
//!
|
||||
//! This is the simple_crypto library. Its goal is to provide straightforward
|
||||
@@ -10,8 +11,8 @@
|
||||
//! when they should use it, and examples. For now, it mostly just fowards
|
||||
//! off to more detailed modules. Help requested!
|
||||
|
||||
extern crate byteorder;
|
||||
extern crate digest;
|
||||
extern crate hmac;
|
||||
extern crate num;
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
@@ -21,26 +22,19 @@ extern crate sha1;
|
||||
extern crate sha2;
|
||||
extern crate simple_asn1;
|
||||
|
||||
/// The `cryptonum` module provides support for large numbers for use in various
|
||||
/// cryptographically-relevant algorithms.
|
||||
/// The cryptonum module provides support for large numbers at fixed,
|
||||
/// cryptographically-relevant sizes.
|
||||
pub mod cryptonum;
|
||||
/// The `rsa` module provides support for RSA-related core algorithms, including
|
||||
/// signing / verification and encryption / decryption. You can also generate
|
||||
/// key material there.
|
||||
/// The RSA module performs the basic operations for RSA, and should
|
||||
/// be used directly only if you're fairly confident about what you're
|
||||
/// doing.
|
||||
pub mod rsa;
|
||||
/// The `dsa` module provides support for DSA-related signing and verification
|
||||
/// algorithms, as well as key generation. That being said: don't use this,
|
||||
/// unless you've got a legacy application or system that you're trying to
|
||||
/// interact with. DSA is almost always the wrong choice.
|
||||
pub mod dsa;
|
||||
/// The 'ecdsa' module provides support for ECDSA-related signing and
|
||||
/// verification algorithms, as well as key generation. This and RSA should be
|
||||
/// your go-to choice for asymmetric crypto.
|
||||
pub mod ecdsa;
|
||||
|
||||
#[cfg(test)]
|
||||
mod testing;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
#[test]
|
||||
fn testing_works() {
|
||||
assert!(true);
|
||||
}
|
||||
}
|
||||
|
||||
180
src/rsa/core.rs
180
src/rsa/core.rs
@@ -1,120 +1,7 @@
|
||||
use cryptonum::{BarrettUCN,UCN};
|
||||
use rand::Rng;
|
||||
|
||||
pub static ACCEPTABLE_KEY_SIZES: [(usize,usize); 8] =
|
||||
[(512, 7),
|
||||
(1024, 7),
|
||||
(2048, 4),
|
||||
(3072, 3),
|
||||
(4096, 3),
|
||||
(7680, 3),
|
||||
(8192, 3),
|
||||
(15360, 3)];
|
||||
|
||||
fn iterations_for_size(l: usize) -> usize {
|
||||
for &(m, i) in ACCEPTABLE_KEY_SIZES.iter() {
|
||||
if m == l {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
panic!("Bad key size, can't get M-R iterations")
|
||||
}
|
||||
|
||||
pub fn generate_pq<G: Rng>(rng: &mut G, e: &UCN, bitlen: usize) -> (UCN, UCN) {
|
||||
let iterations = iterations_for_size(bitlen);
|
||||
let sqrt2 = UCN::from(6074001000 as u64);
|
||||
let topbit = UCN::from(1 as u64) << ((bitlen / 2) - 1);
|
||||
let minval = sqrt2 << ((bitlen / 2) - 33);
|
||||
let mindiff = UCN::from(1 as u64) << ((bitlen / 2) - 101);
|
||||
let validate = |inval| {
|
||||
let x = &inval | &topbit;
|
||||
if x < minval {
|
||||
return None
|
||||
}
|
||||
if !gcd_is_one(&e, &x) {
|
||||
return None
|
||||
}
|
||||
Some(x)
|
||||
};
|
||||
|
||||
let p = UCN::generate_prime(rng, bitlen / 2, iterations, validate);
|
||||
loop {
|
||||
let q = UCN::generate_prime(rng, bitlen / 2, iterations, validate);
|
||||
|
||||
if diff(&p, &q) >= mindiff {
|
||||
return (p, q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn diff(a: &UCN, b: &UCN) -> UCN {
|
||||
if a > b {
|
||||
a - b
|
||||
} else {
|
||||
b - a
|
||||
}
|
||||
}
|
||||
|
||||
fn gcd_is_one(a: &UCN, b: &UCN) -> bool {
|
||||
let mut u = a.clone();
|
||||
let mut v = b.clone();
|
||||
|
||||
if u.is_zero() {
|
||||
return v == UCN::from(1 as u8);
|
||||
}
|
||||
|
||||
if v.is_zero() {
|
||||
return u == UCN::from(1 as u8);
|
||||
}
|
||||
|
||||
if u.is_even() && v.is_even() {
|
||||
return false;
|
||||
}
|
||||
|
||||
while u.is_even() {
|
||||
u >>= 1;
|
||||
}
|
||||
|
||||
loop {
|
||||
while v.is_even() {
|
||||
v >>= 1;
|
||||
}
|
||||
// u and v guaranteed to be odd right now.
|
||||
if u > v {
|
||||
// make sure that v > u, so that our subtraction works
|
||||
// out.
|
||||
let t = u;
|
||||
u = v;
|
||||
v = t;
|
||||
}
|
||||
v = v - &u;
|
||||
|
||||
if v.is_zero() {
|
||||
return u == UCN::from(1 as u64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// the RSA encryption function
|
||||
pub fn ep(nu: &BarrettUCN, e: &UCN, m: &UCN) -> UCN {
|
||||
m.fastmodexp(e, nu)
|
||||
}
|
||||
|
||||
// the RSA decryption function
|
||||
pub fn dp(nu: &BarrettUCN, d: &UCN, c: &UCN) -> UCN {
|
||||
c.fastmodexp(d, nu)
|
||||
}
|
||||
|
||||
// the RSA signature generation function
|
||||
pub fn sp1(nu: &BarrettUCN, d: &UCN, m: &UCN) -> UCN {
|
||||
m.fastmodexp(d, nu)
|
||||
}
|
||||
|
||||
// the RSA signature verification function
|
||||
pub fn vp1(nu: &BarrettUCN, e: &UCN, s: &UCN) -> UCN {
|
||||
s.fastmodexp(e, nu)
|
||||
}
|
||||
use cryptonum::{CryptoNumModOps};
|
||||
use num::BigUint;
|
||||
use rsa::errors::RSAError;
|
||||
use simple_asn1::{ASN1DecodeErr,ASN1Block};
|
||||
|
||||
// encoding PKCS1 stuff
|
||||
pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8> {
|
||||
@@ -132,32 +19,41 @@ pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8> {
|
||||
result
|
||||
}
|
||||
|
||||
// the RSA encryption function
|
||||
pub fn ep<U: CryptoNumModOps>(n: &U, e: &U, m: &U) -> U {
|
||||
m.modexp(e, n)
|
||||
}
|
||||
|
||||
// the RSA decryption function
|
||||
pub fn dp<U: CryptoNumModOps>(n: &U, d: &U, c: &U) -> U {
|
||||
c.modexp(d, n)
|
||||
}
|
||||
|
||||
// the RSA signature generation function
|
||||
pub fn sp1<U: CryptoNumModOps>(n: &U, d: &U, m: &U) -> U {
|
||||
m.modexp(d, n)
|
||||
}
|
||||
|
||||
pub fn decode_biguint(b: &ASN1Block) -> Result<BigUint,RSAError> {
|
||||
match b {
|
||||
&ASN1Block::Integer(_, _, ref v) => {
|
||||
match v.to_biguint() {
|
||||
Some(sn) => Ok(sn),
|
||||
_ => Err(RSAError::InvalidKey)
|
||||
}
|
||||
}
|
||||
_ =>
|
||||
Err(RSAError::ASN1DecodeErr(ASN1DecodeErr::EmptyBuffer))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// the RSA signature verification function
|
||||
pub fn vp1<U: CryptoNumModOps>(n: &U, e: &U, s: &U) -> U {
|
||||
s.modexp(e, n)
|
||||
}
|
||||
|
||||
pub fn xor_vecs(a: &Vec<u8>, b: &Vec<u8>) -> Vec<u8> {
|
||||
a.iter().zip(b.iter()).map(|(a,b)| a^b).collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::OsRng;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn can_get_p_and_q() {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let e = UCN::from(65537 as u64);
|
||||
|
||||
for &(size, _) in ACCEPTABLE_KEY_SIZES.iter().take(3) {
|
||||
let (p,q) = generate_pq(&mut rng, &e, size);
|
||||
let minval = UCN::from(1 as u8) << ((size / 2) - 1);
|
||||
assert!(p > minval);
|
||||
assert!(q > minval);
|
||||
assert!(p != q);
|
||||
assert!(p.is_odd());
|
||||
assert!(q.is_odd());
|
||||
let phi = (p - UCN::from(1 as u64)) * (q - UCN::from(1 as u64));
|
||||
let d = e.modinv(&phi);
|
||||
assert_eq!( (&e * &d) % phi, UCN::from(1 as u64) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use simple_asn1::ASN1DecodeErr;
|
||||
use simple_asn1::{ASN1DecodeErr};
|
||||
use std::io;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -19,6 +19,7 @@ pub enum RSAError {
|
||||
DecryptionError,
|
||||
DecryptHashMismatch,
|
||||
InvalidKey,
|
||||
KeySizeMismatch,
|
||||
RandomGenError(io::Error),
|
||||
ASN1DecodeErr(ASN1DecodeErr)
|
||||
}
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
use rsa::*;
|
||||
use rsa::oaep::OAEPParams;
|
||||
use sha1::Sha1;
|
||||
use sha2::{Sha224,Sha256,Sha384,Sha512};
|
||||
use testing::run_test;
|
||||
|
||||
fn get_signing_hash(s: usize) -> &'static SigningHash {
|
||||
match s {
|
||||
0x1 => &SIGNING_HASH_SHA1,
|
||||
0x224 => &SIGNING_HASH_SHA224,
|
||||
0x256 => &SIGNING_HASH_SHA256,
|
||||
0x384 => &SIGNING_HASH_SHA384,
|
||||
0x512 => &SIGNING_HASH_SHA512,
|
||||
_ => panic!("Unacceptable hash")
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn rsa_signing_tests()
|
||||
{
|
||||
run_test("tests/rsa/signature.test", 7, |case| {
|
||||
let (neg0, dbytes) = case.get("d").unwrap();
|
||||
let (neg1, nbytes) = case.get("n").unwrap();
|
||||
let (neg2, hbytes) = case.get("h").unwrap();
|
||||
let (neg3, kbytes) = case.get("k").unwrap();
|
||||
let (neg4, msg) = case.get("m").unwrap();
|
||||
let (neg5, sig) = case.get("s").unwrap();
|
||||
|
||||
assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4 & !neg5);
|
||||
let hash = get_signing_hash(usize::from(UCN::from_bytes(hbytes)));
|
||||
let size = usize::from(UCN::from_bytes(kbytes));
|
||||
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||
UCN::from_bytes(dbytes));
|
||||
|
||||
assert!(size % 8 == 0);
|
||||
assert_eq!(key.byte_len * 8, size);
|
||||
let sig2 = key.sign(hash, &msg);
|
||||
assert_eq!(*sig, sig2);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rsa_verification_tests()
|
||||
{
|
||||
run_test("tests/rsa/signature.test", 7, |case| {
|
||||
let (neg1, nbytes) = case.get("n").unwrap();
|
||||
let (neg2, hbytes) = case.get("h").unwrap();
|
||||
let (neg3, kbytes) = case.get("k").unwrap();
|
||||
let (neg4, msg) = case.get("m").unwrap();
|
||||
let (neg5, sig) = case.get("s").unwrap();
|
||||
|
||||
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
|
||||
let hash = get_signing_hash(usize::from(UCN::from_bytes(hbytes)));
|
||||
let size = usize::from(UCN::from_bytes(kbytes));
|
||||
let key = RSAPublic::new(UCN::from_bytes(nbytes),
|
||||
UCN::from(65537u64));
|
||||
|
||||
assert_eq!(key.byte_len * 8, size);
|
||||
assert!(key.verify(hash, &msg, sig));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rsa_decryption_tests()
|
||||
{
|
||||
run_test("tests/rsa/encryption.test", 6, |case| {
|
||||
let (neg1, dbytes) = case.get("d").unwrap();
|
||||
let (neg2, nbytes) = case.get("n").unwrap();
|
||||
let (neg3, hbytes) = case.get("h").unwrap();
|
||||
let (neg4, lbytes) = case.get("l").unwrap();
|
||||
let (neg5, msg) = case.get("m").unwrap();
|
||||
let (neg6, cphtxt) = case.get("c").unwrap();
|
||||
|
||||
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
|
||||
let label = String::from_utf8(lbytes.clone()).unwrap();
|
||||
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||
UCN::from_bytes(dbytes));
|
||||
let wrapped = match usize::from(UCN::from_bytes(hbytes)) {
|
||||
0x1 => key.decrypt(&OAEPParams::new(Sha1::default(), label),cphtxt),
|
||||
0x224 => key.decrypt(&OAEPParams::new(Sha224::default(),label),cphtxt),
|
||||
0x256 => key.decrypt(&OAEPParams::new(Sha256::default(),label),cphtxt),
|
||||
0x384 => key.decrypt(&OAEPParams::new(Sha384::default(),label),cphtxt),
|
||||
0x512 => key.decrypt(&OAEPParams::new(Sha512::default(),label),cphtxt),
|
||||
_ => panic!("Unacceptable hash")
|
||||
};
|
||||
let mymsg = wrapped.unwrap();
|
||||
assert_eq!(msg, &mymsg);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn rsa_long_decryption_tests()
|
||||
{
|
||||
run_test("tests/rsa/encryption.ext.test", 6, |case| {
|
||||
let (neg1, dbytes) = case.get("d").unwrap();
|
||||
let (neg2, nbytes) = case.get("n").unwrap();
|
||||
let (neg3, hbytes) = case.get("h").unwrap();
|
||||
let (neg4, lbytes) = case.get("l").unwrap();
|
||||
let (neg5, msg) = case.get("m").unwrap();
|
||||
let (neg6, cphtxt) = case.get("c").unwrap();
|
||||
|
||||
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5 & !neg6);
|
||||
let label = String::from_utf8(lbytes.clone()).unwrap();
|
||||
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||
UCN::from_bytes(dbytes));
|
||||
let wrapped = match usize::from(UCN::from_bytes(hbytes)) {
|
||||
0x1 => key.decrypt(&OAEPParams::new(Sha1::default(), label),cphtxt),
|
||||
0x224 => key.decrypt(&OAEPParams::new(Sha224::default(),label),cphtxt),
|
||||
0x256 => key.decrypt(&OAEPParams::new(Sha256::default(),label),cphtxt),
|
||||
0x384 => key.decrypt(&OAEPParams::new(Sha384::default(),label),cphtxt),
|
||||
0x512 => key.decrypt(&OAEPParams::new(Sha512::default(),label),cphtxt),
|
||||
_ => panic!("Unacceptable hash")
|
||||
};
|
||||
let mymsg = wrapped.unwrap();
|
||||
assert_eq!(msg, &mymsg);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rsa_encryption_tests()
|
||||
{
|
||||
run_test("tests/rsa/encryption.test", 6, |case| {
|
||||
let (neg1, dbytes) = case.get("d").unwrap();
|
||||
let (neg2, nbytes) = case.get("n").unwrap();
|
||||
let (neg3, hbytes) = case.get("h").unwrap();
|
||||
let (neg4, lbytes) = case.get("l").unwrap();
|
||||
let (neg5, msg) = case.get("m").unwrap();
|
||||
|
||||
// This one's a little tricky, because there's randomness in the
|
||||
// encryption phase. So we can't just encrypt and see if we get the
|
||||
// same value. Instead, we just use this as a test vector to round
|
||||
// trip, and trust that the decryption test above makes sure we're
|
||||
// not going off into la la land.
|
||||
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
|
||||
let label = String::from_utf8(lbytes.clone()).unwrap();
|
||||
let private = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||
UCN::from_bytes(dbytes));
|
||||
let public = RSAPublic::new(UCN::from_bytes(nbytes),
|
||||
UCN::from(65537u64));
|
||||
let wrappedc = match usize::from(UCN::from_bytes(hbytes)) {
|
||||
0x1 => public.encrypt(&OAEPParams::new(Sha1::default(), label.clone()), &msg),
|
||||
0x224 => public.encrypt(&OAEPParams::new(Sha224::default(),label.clone()), &msg),
|
||||
0x256 => public.encrypt(&OAEPParams::new(Sha256::default(),label.clone()), &msg),
|
||||
0x384 => public.encrypt(&OAEPParams::new(Sha384::default(),label.clone()), &msg),
|
||||
0x512 => public.encrypt(&OAEPParams::new(Sha512::default(),label.clone()), &msg),
|
||||
_ => panic!("Unacceptable hash")
|
||||
};
|
||||
let ciphertext = wrappedc.unwrap();
|
||||
let wrappedm = match usize::from(UCN::from_bytes(hbytes)) {
|
||||
0x1 => private.decrypt(&OAEPParams::new(Sha1::default(), label), &ciphertext),
|
||||
0x224 => private.decrypt(&OAEPParams::new(Sha224::default(),label), &ciphertext),
|
||||
0x256 => private.decrypt(&OAEPParams::new(Sha256::default(),label), &ciphertext),
|
||||
0x384 => private.decrypt(&OAEPParams::new(Sha384::default(),label), &ciphertext),
|
||||
0x512 => private.decrypt(&OAEPParams::new(Sha512::default(),label), &ciphertext),
|
||||
_ => panic!("Unacceptable hash")
|
||||
};
|
||||
let message = wrappedm.unwrap();
|
||||
|
||||
assert_eq!(msg, &message);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn rsa_long_encryption_tests()
|
||||
{
|
||||
run_test("tests/rsa/encryption.ext.test", 6, |case| {
|
||||
let (neg1, dbytes) = case.get("d").unwrap();
|
||||
let (neg2, nbytes) = case.get("n").unwrap();
|
||||
let (neg3, hbytes) = case.get("h").unwrap();
|
||||
let (neg4, lbytes) = case.get("l").unwrap();
|
||||
let (neg5, msg) = case.get("m").unwrap();
|
||||
|
||||
// This one's a little tricky, because there's randomness in the
|
||||
// encryption phase. So we can't just encrypt and see if we get the
|
||||
// same value. Instead, we just use this as a test vector to round
|
||||
// trip, and trust that the decryption test above makes sure we're
|
||||
// not going off into la la land.
|
||||
assert!(!neg1 & !neg2 & !neg3 & !neg4 & !neg5);
|
||||
let label = String::from_utf8(lbytes.clone()).unwrap();
|
||||
let private = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||
UCN::from_bytes(dbytes));
|
||||
let public = RSAPublic::new(UCN::from_bytes(nbytes),
|
||||
UCN::from(65537u64));
|
||||
let wrappedc = match usize::from(UCN::from_bytes(hbytes)) {
|
||||
0x1 => public.encrypt(&OAEPParams::new(Sha1::default(), label.clone()), &msg),
|
||||
0x224 => public.encrypt(&OAEPParams::new(Sha224::default(),label.clone()), &msg),
|
||||
0x256 => public.encrypt(&OAEPParams::new(Sha256::default(),label.clone()), &msg),
|
||||
0x384 => public.encrypt(&OAEPParams::new(Sha384::default(),label.clone()), &msg),
|
||||
0x512 => public.encrypt(&OAEPParams::new(Sha512::default(),label.clone()), &msg),
|
||||
_ => panic!("Unacceptable hash")
|
||||
};
|
||||
let ciphertext = wrappedc.unwrap();
|
||||
let wrappedm = match usize::from(UCN::from_bytes(hbytes)) {
|
||||
0x1 => private.decrypt(&OAEPParams::new(Sha1::default(), label), &ciphertext),
|
||||
0x224 => private.decrypt(&OAEPParams::new(Sha224::default(),label), &ciphertext),
|
||||
0x256 => private.decrypt(&OAEPParams::new(Sha256::default(),label), &ciphertext),
|
||||
0x384 => private.decrypt(&OAEPParams::new(Sha384::default(),label), &ciphertext),
|
||||
0x512 => private.decrypt(&OAEPParams::new(Sha512::default(),label), &ciphertext),
|
||||
_ => panic!("Unacceptable hash")
|
||||
};
|
||||
let message = wrappedm.unwrap();
|
||||
|
||||
assert_eq!(msg, &message);
|
||||
});
|
||||
}
|
||||
241
src/rsa/mod.rs
241
src/rsa/mod.rs
@@ -1,42 +1,57 @@
|
||||
//! # An implementation of RSA.
|
||||
//!
|
||||
//! This module is designed to provide implementations of the core routines
|
||||
//! used for asymmetric cryptography using RSA. It probably provides a bit
|
||||
//! more flexibility than beginners should play with, and definitely includes
|
||||
//! some capabilities largely targeted at legacy systems. New users should
|
||||
//! probably stick with the stuff in the root of this crate.
|
||||
mod core;
|
||||
mod errors;
|
||||
#[cfg(test)]
|
||||
mod gold_tests;
|
||||
mod oaep;
|
||||
mod public;
|
||||
mod private;
|
||||
mod public;
|
||||
mod signing_hashes;
|
||||
|
||||
pub use self::public::RSAPublic;
|
||||
pub use self::private::RSAPrivate;
|
||||
pub use self::signing_hashes::{SigningHash,
|
||||
SIGNING_HASH_NULL, SIGNING_HASH_SHA1,
|
||||
SIGNING_HASH_SHA224, SIGNING_HASH_SHA256,
|
||||
SIGNING_HASH_SHA384, SIGNING_HASH_SHA512};
|
||||
|
||||
use cryptonum::UCN;
|
||||
use cryptonum::*;
|
||||
use rand::{OsRng,Rng};
|
||||
use self::core::{ACCEPTABLE_KEY_SIZES,generate_pq};
|
||||
use self::errors::*;
|
||||
use std::cmp::PartialOrd;
|
||||
use std::ops::*;
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct RSAKeyPair {
|
||||
pub public: RSAPublic,
|
||||
pub private: RSAPrivate
|
||||
pub use self::errors::{RSAKeyGenError,RSAError};
|
||||
pub use self::oaep::{OAEPParams};
|
||||
pub use self::private::RSAPrivateKey;
|
||||
pub use self::public::RSAPublicKey;
|
||||
pub use self::signing_hashes::{SigningHash,
|
||||
SIGNING_HASH_NULL, SIGNING_HASH_SHA1,
|
||||
SIGNING_HASH_SHA224, SIGNING_HASH_SHA256,
|
||||
SIGNING_HASH_SHA384, SIGNING_HASH_SHA512};
|
||||
|
||||
/// An RSA public and private key.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct RSAKeyPair<Size>
|
||||
where
|
||||
Size: CryptoNumBase + CryptoNumSerialization
|
||||
{
|
||||
pub private: RSAPrivateKey<Size>,
|
||||
pub public: RSAPublicKey<Size>
|
||||
}
|
||||
|
||||
impl RSAKeyPair {
|
||||
/// Generates a fresh RSA key pair of the given bit size. Valid bit sizes
|
||||
/// are 512, 1024, 2048, 3072, 4096, 7680, 8192, and 15360. If you
|
||||
/// actually want to protect data, use a value greater than or equal to
|
||||
/// 2048. If you don't want to spend all day waiting for RSA computations
|
||||
/// to finish, choose a value less than or equal to 4096.
|
||||
impl<T> RSAKeyPair<T>
|
||||
where
|
||||
T: Clone + Sized + PartialOrd + From<u64>,
|
||||
T: CryptoNumBase + CryptoNumModOps + CryptoNumPrimes + CryptoNumSerialization,
|
||||
T: Sub<Output=T> + Mul<Output=T> + Shl<usize,Output=T>
|
||||
{
|
||||
/// Generates a fresh RSA key pair. If you actually want to protect data,
|
||||
/// use a value greater than or equal to 2048. If you don't want to spend
|
||||
/// all day waiting for RSA computations to finish, choose a value less
|
||||
/// than or equal to 4096.
|
||||
///
|
||||
/// This routine will use `OsRng` for entropy. If you want to use your
|
||||
/// own random number generator, use `generate_w_rng`.
|
||||
pub fn generate(len_bits: usize) -> Result<RSAKeyPair,RSAKeyGenError> {
|
||||
pub fn generate() -> Result<RSAKeyPair<T>,RSAKeyGenError> {
|
||||
let mut rng = OsRng::new()?;
|
||||
RSAKeyPair::generate_w_rng(&mut rng, len_bits)
|
||||
RSAKeyPair::<T>::generate_w_rng(&mut rng)
|
||||
}
|
||||
|
||||
/// Generates a fresh RSA key pair of the given bit size. Valid bit sizes
|
||||
@@ -49,61 +64,165 @@ impl RSAKeyPair {
|
||||
/// you should know what you're doing, and be using a cryptographically-
|
||||
/// strong RNG of your own choosing. We've warned you. Use a good one.
|
||||
/// So now it's on you.
|
||||
pub fn generate_w_rng<G: Rng>(rng: &mut G, len_bits: usize)
|
||||
-> Result<RSAKeyPair,RSAKeyGenError>
|
||||
pub fn generate_w_rng<G: Rng>(rng: &mut G)
|
||||
-> Result<RSAKeyPair<T>,RSAKeyGenError>
|
||||
{
|
||||
let e = UCN::from(65537 as u32);
|
||||
|
||||
for &(length, _) in ACCEPTABLE_KEY_SIZES.iter() {
|
||||
if length == len_bits {
|
||||
let (p, q) = generate_pq(rng, &e, len_bits);
|
||||
let n = &p * &q;
|
||||
let one = UCN::from(1 as u8);
|
||||
let phi = (p - &one) * (q - &one);
|
||||
let e = T::from(65537);
|
||||
let len_bits = e.bit_size();
|
||||
match generate_pq(rng, &e) {
|
||||
None =>
|
||||
return Err(RSAKeyGenError::InvalidKeySize(len_bits)),
|
||||
Some((p, q)) => {
|
||||
let n = p.clone() * q.clone();
|
||||
let phi = (p - T::from(1)) * (q - T::from(1));
|
||||
let d = e.modinv(&phi);
|
||||
let public_key = RSAPublic::new(n.clone(), e);
|
||||
let private_key = RSAPrivate::new(n, d);
|
||||
return Ok(RSAKeyPair{
|
||||
private: private_key,
|
||||
public: public_key
|
||||
})
|
||||
let public_key = RSAPublicKey::new(n.clone(), e);
|
||||
let private_key = RSAPrivateKey::new(n, d);
|
||||
return Ok(RSAKeyPair{ private: private_key, public: public_key })
|
||||
}
|
||||
}
|
||||
|
||||
Err(RSAKeyGenError::InvalidKeySize(len_bits))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_pq<'a,G,T>(rng: &mut G, e: &T) -> Option<(T,T)>
|
||||
where
|
||||
G: Rng,
|
||||
T: Clone + PartialOrd + Shl<usize,Output=T> + Sub<Output=T> + From<u64>,
|
||||
T: CryptoNumBase + CryptoNumPrimes + CryptoNumSerialization
|
||||
{
|
||||
let bitlen = T::zero().bit_size();
|
||||
let mindiff = T::from(1) << ((bitlen/2)-101);
|
||||
let minval = T::from(6074001000) << ((mindiff.bit_size()/2) - 33);
|
||||
let p = T::generate_prime(rng, 7, e, &minval);
|
||||
|
||||
loop {
|
||||
let q = T::generate_prime(rng, 7, e, &minval);
|
||||
|
||||
if diff(p.clone(), q.clone()) >= mindiff {
|
||||
return Some((p, q));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn diff<T: PartialOrd + Sub<Output=T>>(a: T, b: T) -> T
|
||||
{
|
||||
if a > b {
|
||||
a - b
|
||||
} else {
|
||||
b - a
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use quickcheck::{Arbitrary,Gen};
|
||||
use rsa::core::{ep,dp,sp1,vp1};
|
||||
use rsa::core::{dp,ep,sp1,vp1};
|
||||
use sha2::Sha224;
|
||||
use simple_asn1::{der_decode,der_encode};
|
||||
use super::*;
|
||||
|
||||
const TEST_KEY_SIZES: [usize; 2] = [512, 1024];
|
||||
impl Arbitrary for RSAKeyPair<U512> {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair<U512> {
|
||||
RSAKeyPair::generate_w_rng(g).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Arbitrary for RSAKeyPair {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair {
|
||||
let size = g.choose(&TEST_KEY_SIZES).unwrap();
|
||||
RSAKeyPair::generate_w_rng(g, *size).unwrap()
|
||||
// Core primitive checks
|
||||
quickcheck! {
|
||||
fn ep_dp_inversion(kp: RSAKeyPair<U512>, m: U512) -> bool {
|
||||
let realm = &m % &kp.public.n;
|
||||
let ciphertext = ep(&kp.public.n, &kp.public.e, &realm);
|
||||
let mprime = dp(&kp.private.n, &kp.private.d, &ciphertext);
|
||||
mprime == m
|
||||
}
|
||||
fn sp_vp_inversion(kp: RSAKeyPair<U512>, m: U512) -> bool {
|
||||
let realm = &m % &kp.public.n;
|
||||
let sig = sp1(&kp.private.n, &kp.private.d, &realm);
|
||||
let mprime = vp1(&kp.public.n, &kp.public.e, &sig);
|
||||
mprime == m
|
||||
}
|
||||
}
|
||||
|
||||
// Public key serialization
|
||||
quickcheck! {
|
||||
fn asn1_encoding_inverts(kp: RSAKeyPair<U512>) -> bool {
|
||||
let bytes = der_encode(&kp.public).unwrap();
|
||||
let pubkey: RSAPublicKey<U512> = der_decode(&bytes).unwrap();
|
||||
(pubkey.n == kp.public.n) && (pubkey.e == kp.public.e)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
struct Message {
|
||||
m: Vec<u8>
|
||||
}
|
||||
|
||||
impl Arbitrary for Message {
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> Message {
|
||||
let len = 1 + (g.gen::<u8>() % 3);
|
||||
let mut storage = Vec::new();
|
||||
for _ in 0..len {
|
||||
storage.push(g.gen::<u8>());
|
||||
}
|
||||
Message{ m: storage }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
struct KeyPairAndSigHash<T>
|
||||
where
|
||||
T: CryptoNumSerialization + CryptoNumBase
|
||||
{
|
||||
kp: RSAKeyPair<T>,
|
||||
sh: &'static SigningHash
|
||||
}
|
||||
|
||||
impl<T> Arbitrary for KeyPairAndSigHash<T>
|
||||
where
|
||||
T: Clone + Sized + PartialOrd + From<u64>,
|
||||
T: CryptoNumBase + CryptoNumModOps,
|
||||
T: CryptoNumPrimes + CryptoNumSerialization,
|
||||
T: Sub<Output=T> + Mul<Output=T> + Shl<usize,Output=T>,
|
||||
RSAKeyPair<T>: Arbitrary
|
||||
{
|
||||
fn arbitrary<G: Gen>(g: &mut G) -> KeyPairAndSigHash<T> {
|
||||
let kp = RSAKeyPair::generate_w_rng(g).unwrap();
|
||||
let size = kp.public.n.bit_size();
|
||||
let mut hashes = vec![&SIGNING_HASH_SHA1];
|
||||
|
||||
if size >= 1024 {
|
||||
hashes.push(&SIGNING_HASH_SHA224);
|
||||
}
|
||||
|
||||
if size >= 2048 {
|
||||
hashes.push(&SIGNING_HASH_SHA256);
|
||||
}
|
||||
|
||||
if size >= 4096 {
|
||||
hashes.push(&SIGNING_HASH_SHA384);
|
||||
hashes.push(&SIGNING_HASH_SHA512);
|
||||
}
|
||||
|
||||
let hash = g.choose(&hashes).unwrap().clone();
|
||||
KeyPairAndSigHash{ kp: kp, sh: hash }
|
||||
}
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
#[ignore]
|
||||
fn rsa_ep_dp_inversion(kp: RSAKeyPair, n: UCN) -> bool {
|
||||
let m = n.reduce(&kp.public.nu);
|
||||
let ciphertext = ep(&kp.public.nu, &kp.public.e, &m);
|
||||
let mprime = dp(&kp.private.nu, &kp.private.d, &ciphertext);
|
||||
mprime == m
|
||||
fn sign_verifies(kpsh: KeyPairAndSigHash<U512>, m: Message) -> bool {
|
||||
let sig = kpsh.kp.private.sign(kpsh.sh, &m.m);
|
||||
kpsh.kp.public.verify(kpsh.sh, &m.m, &sig)
|
||||
}
|
||||
#[ignore]
|
||||
fn rsa_sp_vp_inversion(kp: RSAKeyPair, n: UCN) -> bool {
|
||||
let m = n.reduce(&kp.public.nu);
|
||||
let sig = sp1(&kp.private.nu, &kp.private.d, &m);
|
||||
let mprime = vp1(&kp.public.nu, &kp.public.e, &sig);
|
||||
mprime == m
|
||||
|
||||
fn enc_dec_roundtrips(kp: RSAKeyPair<U512>, m: Message) -> bool {
|
||||
let oaep = OAEPParams {
|
||||
hash: Sha224::default(),
|
||||
label: "test".to_string()
|
||||
};
|
||||
let c = kp.public.encrypt(&oaep, &m.m).unwrap();
|
||||
let mp = kp.private.decrypt(&oaep, &c).unwrap();
|
||||
|
||||
mp == m.m
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use cryptonum::UCN;
|
||||
use byteorder::{BigEndian,ByteOrder};
|
||||
use digest::{FixedOutput,Input};
|
||||
|
||||
/// Parameters for OAEP encryption and decryption: a hash function to use as part of the message
|
||||
/// generation function (MGF1, if you're curious), and any labels you want to include as part of
|
||||
/// the encryption.
|
||||
/// Parameters for OAEP encryption and decryption: a hash function to use
|
||||
/// as part of the message generation function (MGF1, if you're curious),
|
||||
/// and any labels you want to include as part of the encryption.
|
||||
pub struct OAEPParams<H: Clone + Input + FixedOutput> {
|
||||
pub hash: H,
|
||||
pub label: String
|
||||
@@ -28,17 +28,17 @@ impl<H: Clone + Input + FixedOutput> OAEPParams<H> {
|
||||
|
||||
pub fn mgf1(&self, input: &[u8], len: usize) -> Vec<u8> {
|
||||
let mut res = Vec::with_capacity(len);
|
||||
let mut counter = UCN::from(0u64);
|
||||
let one = UCN::from(1u64);
|
||||
let mut counter: u32 = 0;
|
||||
|
||||
while res.len() < len {
|
||||
let c = counter.to_bytes(4);
|
||||
let mut c: [u8; 4] = [0; 4];
|
||||
BigEndian::write_u32(&mut c, counter);
|
||||
let mut digest = self.hash.clone();
|
||||
digest.process(input);
|
||||
digest.process(&c);
|
||||
let chunk = digest.fixed_result();
|
||||
res.extend_from_slice(chunk.as_slice());
|
||||
counter = counter + &one;
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
res.truncate(len);
|
||||
|
||||
@@ -1,77 +1,43 @@
|
||||
use cryptonum::{BarrettUCN,UCN};
|
||||
use cryptonum::{CryptoNumBase,CryptoNumModOps,CryptoNumSerialization};
|
||||
use digest::{FixedOutput,Input};
|
||||
use rsa::core::{ACCEPTABLE_KEY_SIZES,dp,pkcs1_pad,sp1,xor_vecs};
|
||||
use rsa::errors::RSAError;
|
||||
use rsa::oaep::OAEPParams;
|
||||
use rsa::core::{dp,sp1,pkcs1_pad,xor_vecs};
|
||||
use rsa::oaep::{OAEPParams};
|
||||
use rsa::errors::{RSAError};
|
||||
use rsa::signing_hashes::SigningHash;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RSAPrivate {
|
||||
pub(crate) byte_len: usize,
|
||||
pub(crate) n: UCN,
|
||||
pub(crate) nu: BarrettUCN,
|
||||
pub(crate) d: UCN
|
||||
/// A RSA private key. As with public keys, I've left the size as a
|
||||
/// parameter: 2048-4096 is standard practice, 512-1024 is weak, and
|
||||
/// >4096 is going to be slow.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct RSAPrivateKey<Size>
|
||||
where
|
||||
Size: CryptoNumBase + CryptoNumSerialization
|
||||
{
|
||||
pub(crate) n: Size,
|
||||
pub(crate) d: Size
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl fmt::Debug for RSAPrivate {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("RSAPrivate")
|
||||
.field("byte_len", &self.byte_len)
|
||||
.field("n", &self.n)
|
||||
.field("nu", &self.nu)
|
||||
.field("d", &self.d)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl PartialEq for RSAPrivate {
|
||||
fn eq(&self, rhs: &RSAPrivate) -> bool {
|
||||
(self.byte_len == rhs.byte_len) &&
|
||||
(self.n == rhs.n) &&
|
||||
(self.nu == rhs.nu) &&
|
||||
(self.d == rhs.d)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Eq for RSAPrivate {}
|
||||
|
||||
#[cfg(not(test))]
|
||||
impl fmt::Debug for RSAPrivate {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("RSAPrivateKey<PRIVATE>")
|
||||
}
|
||||
}
|
||||
|
||||
impl RSAPrivate {
|
||||
/// Create a new RSA public key from the given components, which you found
|
||||
/// via some other mechanism.
|
||||
pub fn new(n: UCN, d: UCN) -> RSAPrivate {
|
||||
let len = n.bits();
|
||||
|
||||
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
|
||||
if valid_bits >= len {
|
||||
return RSAPrivate {
|
||||
byte_len: valid_bits / 8,
|
||||
n: n.clone(),
|
||||
nu: n.barrett_u(),
|
||||
d: d.clone()
|
||||
};
|
||||
}
|
||||
impl<U> RSAPrivateKey<U>
|
||||
where
|
||||
U: CryptoNumBase + CryptoNumModOps + CryptoNumSerialization
|
||||
{
|
||||
/// Generate a private key, using the given `n` and `d` parameters
|
||||
/// gathered from some other source. The length should be given in
|
||||
/// bits.
|
||||
pub fn new(n: U, d: U) -> RSAPrivateKey<U> {
|
||||
RSAPrivateKey {
|
||||
n: n,
|
||||
d: d
|
||||
}
|
||||
panic!("Invalid RSA key size in new()")
|
||||
}
|
||||
|
||||
/// Sign a message using the given hash.
|
||||
pub fn sign(&self, sighash: &SigningHash, msg: &[u8]) -> Vec<u8> {
|
||||
let hash = (sighash.run)(msg);
|
||||
let em = pkcs1_pad(&sighash.ident, &hash, self.byte_len);
|
||||
let m = UCN::from_bytes(&em);
|
||||
let s = sp1(&self.nu, &self.d, &m);
|
||||
let sig = s.to_bytes(self.byte_len);
|
||||
let em = pkcs1_pad(&sighash.ident, &hash, self.d.byte_size());
|
||||
let m = U::from_bytes(&em);
|
||||
let s = sp1(&self.n, &self.d, &m);
|
||||
let sig = s.to_bytes();
|
||||
sig
|
||||
}
|
||||
|
||||
@@ -80,8 +46,9 @@ impl RSAPrivate {
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
{
|
||||
let mut res = Vec::new();
|
||||
let byte_len = self.d.byte_size();
|
||||
|
||||
for chunk in msg.chunks(self.byte_len) {
|
||||
for chunk in msg.chunks(byte_len) {
|
||||
let mut dchunk = self.oaep_decrypt(oaep, chunk)?;
|
||||
res.append(&mut dchunk);
|
||||
}
|
||||
@@ -92,20 +59,21 @@ impl RSAPrivate {
|
||||
fn oaep_decrypt<H: Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, c: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
{
|
||||
let byte_len = self.d.byte_size();
|
||||
// Step 1b
|
||||
if c.len() != self.byte_len {
|
||||
if c.len() != byte_len {
|
||||
return Err(RSAError::DecryptionError);
|
||||
}
|
||||
// Step 1c
|
||||
if self.byte_len < ((2 * oaep.hash_len()) + 2) {
|
||||
if byte_len < ((2 * oaep.hash_len()) + 2) {
|
||||
return Err(RSAError::DecryptHashMismatch);
|
||||
}
|
||||
// Step 2a
|
||||
let c_ip = UCN::from_bytes(&c.to_vec());
|
||||
let c_ip = U::from_bytes(&c);
|
||||
// Step 2b
|
||||
let m_ip = dp(&self.nu, &self.d, &c_ip);
|
||||
let m_ip = dp(&self.n, &self.d, &c_ip);
|
||||
// Step 2c
|
||||
let em = &m_ip.to_bytes(self.byte_len);
|
||||
let em = m_ip.to_bytes();
|
||||
// Step 3a
|
||||
let l_hash = oaep.hash(oaep.label.as_bytes());
|
||||
// Step 3b
|
||||
@@ -116,7 +84,7 @@ impl RSAPrivate {
|
||||
// Step 3d
|
||||
let seed = xor_vecs(&masked_seed.to_vec(), &seed_mask);
|
||||
// Step 3e
|
||||
let db_mask = oaep.mgf1(&seed, self.byte_len - oaep.hash_len() - 1);
|
||||
let db_mask = oaep.mgf1(&seed, byte_len - oaep.hash_len() - 1);
|
||||
// Step 3f
|
||||
let db = xor_vecs(&masked_db.to_vec(), &db_mask);
|
||||
// Step 3g
|
||||
|
||||
@@ -1,47 +1,49 @@
|
||||
use cryptonum::{BarrettUCN,UCN};
|
||||
use cryptonum::{CryptoNumBase,CryptoNumModOps,CryptoNumSerialization};
|
||||
use digest::{FixedOutput,Input};
|
||||
use num::{BigInt,BigUint};
|
||||
use rand::{OsRng,Rng};
|
||||
use rsa::core::{ACCEPTABLE_KEY_SIZES,ep,pkcs1_pad,vp1,xor_vecs};
|
||||
use rsa::errors::RSAError;
|
||||
use rsa::oaep::OAEPParams;
|
||||
use rsa::core::{ep,vp1,pkcs1_pad,xor_vecs,decode_biguint};
|
||||
use rsa::oaep::{OAEPParams};
|
||||
use rsa::errors::{RSAError};
|
||||
use rsa::signing_hashes::SigningHash;
|
||||
use simple_asn1::{FromASN1,ToASN1,ASN1DecodeErr,ASN1EncodeErr};
|
||||
use simple_asn1::{ASN1Block,ASN1Class};
|
||||
|
||||
#[derive(Clone,Debug,PartialEq,Eq)]
|
||||
pub struct RSAPublic {
|
||||
pub(crate) byte_len: usize,
|
||||
pub(crate) n: UCN,
|
||||
pub(crate) nu: BarrettUCN,
|
||||
pub(crate) e: UCN
|
||||
/// An RSA public key with the given modulus size. I've left the size as a
|
||||
/// parameter, instead of hardcoding particular values. That being said,
|
||||
/// you almost certainly want one of `U2048`, `U3072`, or `U4096` if you're
|
||||
/// being pretty standard; `U512` or `U1024` if you're interfacing with
|
||||
/// legacy code or want to build intentionally weak systems; or `U7680`,
|
||||
/// `U8192`, or `U15360` if you like things running very slowly.
|
||||
#[derive(Clone,Debug,PartialEq)]
|
||||
pub struct RSAPublicKey<Size>
|
||||
where
|
||||
Size: CryptoNumBase + CryptoNumSerialization
|
||||
{
|
||||
pub(crate) n: Size,
|
||||
pub(crate) e: Size
|
||||
}
|
||||
|
||||
impl RSAPublic {
|
||||
impl<U> RSAPublicKey<U>
|
||||
where
|
||||
U: CryptoNumBase + CryptoNumModOps + CryptoNumSerialization
|
||||
{
|
||||
/// Create a new RSA public key from the given components, which you found
|
||||
/// via some other mechanism.
|
||||
pub fn new(n: UCN, e: UCN) -> RSAPublic {
|
||||
let len = n.bits();
|
||||
|
||||
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
|
||||
if valid_bits >= len {
|
||||
return RSAPublic{
|
||||
byte_len: valid_bits / 8,
|
||||
n: n.clone(),
|
||||
nu: n.barrett_u(),
|
||||
e: e.clone()
|
||||
};
|
||||
}
|
||||
}
|
||||
panic!("Invalid RSA key size in new()")
|
||||
pub fn new(n: U, e: U) -> RSAPublicKey<U> {
|
||||
RSAPublicKey{ n: n, e: e }
|
||||
}
|
||||
|
||||
/// Verify the signature for a given message, using the given signing hash,
|
||||
/// returning true iff the signature validates.
|
||||
pub fn verify(&self, shash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool {
|
||||
let hash = (shash.run)(msg);
|
||||
let s = UCN::from_bytes(&sig);
|
||||
let m = vp1(&self.nu, &self.e, &s);
|
||||
let em = m.to_bytes(self.byte_len);
|
||||
let em_ = pkcs1_pad(&shash.ident, &hash, self.byte_len);
|
||||
(em == em_)
|
||||
/// return true iff the signature validates.
|
||||
pub fn verify(&self, sighash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool
|
||||
{
|
||||
let hash = (sighash.run)(msg);
|
||||
let s = U::from_bytes(sig);
|
||||
let m = vp1(&self.n, &self.e, &s);
|
||||
let em = s.to_bytes();
|
||||
let em_ = pkcs1_pad(&sighash.ident, &hash, m.byte_size());
|
||||
em == em_
|
||||
}
|
||||
|
||||
/// Encrypt the given data with the public key and parameters, returning
|
||||
@@ -50,7 +52,8 @@ impl RSAPublic {
|
||||
/// OAEP encoding is used for this process, which requires a random number
|
||||
/// generator. This version of the function uses `OsRng`. If you want to
|
||||
/// use your own RNG, use `encrypt_w_rng`.
|
||||
pub fn encrypt<H:Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
pub fn encrypt<H:Clone + Input + FixedOutput>(&self, oaep: &OAEPParams<H>,
|
||||
msg: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
{
|
||||
let mut g = OsRng::new()?;
|
||||
@@ -61,17 +64,20 @@ impl RSAPublic {
|
||||
/// the encrypted blob or an error encountered during encryption. This
|
||||
/// version also allows you to provide your own RNG, if you really feel
|
||||
/// like shooting yourself in the foot.
|
||||
pub fn encrypt_with_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
pub fn encrypt_with_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>,
|
||||
msg: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
where G: Rng, H: Clone + Input + FixedOutput
|
||||
{
|
||||
if self.byte_len <= ((2 * oaep.hash_len()) + 2) {
|
||||
let mylen = self.e.byte_size();
|
||||
|
||||
if mylen <= ((2 * oaep.hash_len()) + 2) {
|
||||
return Err(RSAError::KeyTooSmallForHash);
|
||||
}
|
||||
|
||||
let mut res = Vec::new();
|
||||
|
||||
for chunk in msg.chunks(self.byte_len - (2 * oaep.hash_len()) - 2) {
|
||||
for chunk in msg.chunks(mylen - (2 * oaep.hash_len()) - 2) {
|
||||
let mut newchunk = self.oaep_encrypt(g, oaep, chunk)?;
|
||||
res.append(&mut newchunk)
|
||||
}
|
||||
@@ -79,17 +85,21 @@ impl RSAPublic {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn oaep_encrypt<G: Rng,H:Clone + Input + FixedOutput>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
fn oaep_encrypt<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
|
||||
-> Result<Vec<u8>,RSAError>
|
||||
where
|
||||
G: Rng, H:Clone + Input + FixedOutput
|
||||
{
|
||||
let mylen = self.e.byte_size();
|
||||
|
||||
// Step 1b
|
||||
if msg.len() > (self.byte_len - (2 * oaep.hash_len()) - 2) {
|
||||
if msg.len() > (mylen - (2 * oaep.hash_len()) - 2) {
|
||||
return Err(RSAError::BadMessageSize)
|
||||
}
|
||||
// Step 2a
|
||||
let mut lhash = oaep.hash(oaep.label.as_bytes());
|
||||
// Step 2b
|
||||
let num0s = self.byte_len - msg.len() - (2 * oaep.hash_len()) - 2;
|
||||
let num0s = mylen - msg.len() - (2 * oaep.hash_len()) - 2;
|
||||
let mut ps = Vec::new();
|
||||
ps.resize(num0s, 0);
|
||||
// Step 2c
|
||||
@@ -101,7 +111,7 @@ impl RSAPublic {
|
||||
// Step 2d
|
||||
let seed : Vec<u8> = g.gen_iter().take(oaep.hash_len()).collect();
|
||||
// Step 2e
|
||||
let db_mask = oaep.mgf1(&seed, self.byte_len - oaep.hash_len() - 1);
|
||||
let db_mask = oaep.mgf1(&seed, mylen - oaep.hash_len() - 1);
|
||||
// Step 2f
|
||||
let mut masked_db = xor_vecs(&db, &db_mask);
|
||||
// Step 2g
|
||||
@@ -114,11 +124,73 @@ impl RSAPublic {
|
||||
em.append(&mut masked_seed);
|
||||
em.append(&mut masked_db);
|
||||
// Step 3a
|
||||
let m_i = UCN::from_bytes(&em);
|
||||
let m_i = U::from_bytes(&em);
|
||||
// Step 3b
|
||||
let c_i = ep(&self.nu, &self.e, &m_i);
|
||||
let c_i = ep(&self.n, &self.e, &m_i);
|
||||
// Step 3c
|
||||
let c = c_i.to_bytes(self.byte_len);
|
||||
let c = c_i.to_bytes();
|
||||
Ok(c)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromASN1 for RSAPublicKey<T>
|
||||
where
|
||||
T: CryptoNumBase + CryptoNumSerialization,
|
||||
T: From<BigUint>
|
||||
{
|
||||
type Error = RSAError;
|
||||
|
||||
fn from_asn1(bs: &[ASN1Block])
|
||||
-> Result<(RSAPublicKey<T>,&[ASN1Block]),RSAError>
|
||||
{
|
||||
match bs.split_first() {
|
||||
None =>
|
||||
Err(RSAError::ASN1DecodeErr(ASN1DecodeErr::EmptyBuffer)),
|
||||
Some((&ASN1Block::Sequence(_, _, ref items), rest))
|
||||
if items.len() == 2 =>
|
||||
{
|
||||
let numn = decode_biguint(&items[0])?;
|
||||
let nume = decode_biguint(&items[1])?;
|
||||
let nsize = numn.bits();
|
||||
let mut rsa_size = 512;
|
||||
|
||||
while rsa_size < nsize {
|
||||
rsa_size = rsa_size + 256;
|
||||
}
|
||||
rsa_size /= 8;
|
||||
|
||||
if rsa_size != (T::zero()).bit_size() {
|
||||
return Err(RSAError::KeySizeMismatch);
|
||||
}
|
||||
|
||||
let n = T::from(numn);
|
||||
let e = T::from(nume);
|
||||
|
||||
let res = RSAPublicKey{ n: n, e: e };
|
||||
|
||||
Ok((res, rest))
|
||||
}
|
||||
Some(_) =>
|
||||
Err(RSAError::InvalidKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToASN1 for RSAPublicKey<T>
|
||||
where
|
||||
T: Clone + Into<BigInt>,
|
||||
T: CryptoNumBase + CryptoNumSerialization
|
||||
{
|
||||
type Error = ASN1EncodeErr;
|
||||
|
||||
fn to_asn1_class(&self, c: ASN1Class)
|
||||
-> Result<Vec<ASN1Block>,Self::Error>
|
||||
{
|
||||
let enc_n = ASN1Block::Integer(c, 0, self.n.clone().into());
|
||||
let enc_e = ASN1Block::Integer(c, 0, self.e.clone().into());
|
||||
let seq = ASN1Block::Sequence(c, 0, vec![enc_n, enc_e]);
|
||||
Ok(vec![seq])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
use cryptonum::{SCN,UCN};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::str::Lines;
|
||||
|
||||
fn next_value_set(line: &str) -> (String, bool, Vec<u8>)
|
||||
{
|
||||
assert!(line.is_ascii());
|
||||
let mut items = line.split(": ");
|
||||
let key = items.next().unwrap();
|
||||
let valbits = items.next().unwrap();
|
||||
let neg = valbits.contains('-');
|
||||
let valbitsnoneg = valbits.trim_left_matches("-");
|
||||
|
||||
let mut nibble_iter = valbitsnoneg.chars().rev();
|
||||
let mut val = Vec::new();
|
||||
|
||||
while let Some(c1) = nibble_iter.next() {
|
||||
match nibble_iter.next() {
|
||||
None => {
|
||||
val.push( c1.to_digit(16).unwrap() as u8 );
|
||||
}
|
||||
Some(c2) => {
|
||||
let b1 = c1.to_digit(16).unwrap() as u8;
|
||||
let b2 = c2.to_digit(16).unwrap() as u8;
|
||||
val.push( (b2 << 4) | b1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
val.reverse();
|
||||
|
||||
(key.to_string(), neg, val)
|
||||
}
|
||||
|
||||
fn next_test_case(contents: &mut Lines, lines: usize) ->
|
||||
Option<HashMap<String,(bool,Vec<u8>)>>
|
||||
{
|
||||
let mut res = HashMap::new();
|
||||
let mut count = 0;
|
||||
|
||||
while count < lines {
|
||||
let line = contents.next()?;
|
||||
let (key, neg, val) = next_value_set(line);
|
||||
res.insert(key, (neg,val));
|
||||
count += 1;
|
||||
}
|
||||
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn make_signed(m: HashMap<String,(bool,Vec<u8>)>) -> HashMap<String,SCN>
|
||||
{
|
||||
let mut res: HashMap<String,SCN> = HashMap::new();
|
||||
|
||||
for (key, (neg, bval)) in m.iter() {
|
||||
let base = UCN::from_bytes(bval);
|
||||
let val = SCN{ negative: *neg, value: base };
|
||||
res.insert(key.clone(), val);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn make_unsigned(m: HashMap<String,(bool,Vec<u8>)>) -> HashMap<String,UCN>
|
||||
{
|
||||
let mut res: HashMap<String,UCN> = HashMap::new();
|
||||
|
||||
for (key, (neg, bval)) in m.iter() {
|
||||
assert!(!neg);
|
||||
res.insert(key.clone(), UCN::from_bytes(bval));
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
pub fn run_test<F>(fname: &'static str, i: usize, f: F)
|
||||
where F: Fn(HashMap<String,(bool,Vec<u8>)>)
|
||||
{
|
||||
let mut file = File::open(fname).unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
let mut iter = contents.lines();
|
||||
|
||||
while let Some(scase) = next_test_case(&mut iter, i) {
|
||||
f(scase);
|
||||
}
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
// Just because I always forget Java compilation:
|
||||
// javac Generator.java -cp bcprov-ext-jdk15on-159.jar
|
||||
// java -cp "bcprov-ext-jdk15on-159.jar:." Generator
|
||||
// Also, go here:
|
||||
// https://www.bouncycastle.org/latest_releases.html
|
||||
//
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.InterruptedException;
|
||||
import java.lang.Math;
|
||||
import java.lang.Thread;
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA1Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA224Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA256Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA384Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA512Digest;
|
||||
import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
|
||||
import org.bouncycastle.crypto.generators.DSAParametersGenerator;
|
||||
import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
|
||||
import org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
|
||||
import org.bouncycastle.crypto.params.DSAParameters;
|
||||
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
|
||||
import org.bouncycastle.crypto.signers.DSASigner;
|
||||
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
|
||||
|
||||
class Generator {
|
||||
private FileWriter out;
|
||||
private SecureRandom rng;
|
||||
|
||||
final static int NUM_THREADS = 4;
|
||||
|
||||
public Generator(SecureRandom r, FileWriter o) {
|
||||
rng = r;
|
||||
out = o;
|
||||
}
|
||||
|
||||
public void runTests(int lsize, int nsize, int count)
|
||||
throws IOException, InterruptedException
|
||||
{
|
||||
Thread threads[] = new Thread[NUM_THREADS];
|
||||
|
||||
System.out.print("Generating L" + lsize + "N" + nsize + " tests ");
|
||||
for(int i = 0; i < NUM_THREADS; i++) {
|
||||
Runner runner = new Runner(lsize, nsize, count / NUM_THREADS, this);
|
||||
Thread runThread = new Thread(runner);
|
||||
runThread.start();
|
||||
threads[i] = runThread;
|
||||
}
|
||||
for(Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
System.out.println(" done.");
|
||||
}
|
||||
|
||||
public synchronized void output(DSAParameters params,
|
||||
AsymmetricCipherKeyPair kp,
|
||||
int digestsize,
|
||||
byte[] message,
|
||||
BigInteger[] rs)
|
||||
throws IOException
|
||||
{
|
||||
DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic();
|
||||
DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate();
|
||||
out.write("p: " + params.getP().toString(16) + "\n");
|
||||
out.write("q: " + params.getQ().toString(16) + "\n");
|
||||
out.write("g: " + params.getG().toString(16) + "\n");
|
||||
out.write("x: " + priv.getX().toString(16) + "\n");
|
||||
out.write("y: " + pub.getY().toString(16) + "\n");
|
||||
out.write("h: " + digestsize + "\n");
|
||||
out.write("m: " + asHex(message) + "\n");
|
||||
out.write("r: " + rs[0].toString(16) + "\n");
|
||||
out.write("s: " + rs[1].toString(16) + "\n");
|
||||
out.flush();
|
||||
System.out.print(".");
|
||||
System.out.flush();
|
||||
}
|
||||
|
||||
private Digest appropriateDigest(int nsize)
|
||||
throws IOException
|
||||
{
|
||||
switch(nsize) {
|
||||
case 1: return new SHA1Digest();
|
||||
case 160: return new SHA1Digest();
|
||||
case 224: return new SHA224Digest();
|
||||
case 256: return new SHA256Digest();
|
||||
case 384: return new SHA384Digest();
|
||||
case 512: return new SHA512Digest();
|
||||
default:
|
||||
throw new IOException("Bad digest size!");
|
||||
}
|
||||
}
|
||||
|
||||
private int randomDigestSize()
|
||||
throws IOException
|
||||
{
|
||||
switch(getRandomChoice(5)) {
|
||||
case 0: return 1;
|
||||
case 1: return 224;
|
||||
case 2: return 256;
|
||||
case 3: return 384;
|
||||
case 4: return 512;
|
||||
default:
|
||||
throw new IOException("The world broke.");
|
||||
}
|
||||
}
|
||||
|
||||
private int getRandomChoice(int modulus) {
|
||||
byte randoms[] = new byte[2];
|
||||
rng.nextBytes(randoms);
|
||||
int random = ((int)randoms[0] << 8) + ((int)randoms[1]);
|
||||
return (Math.abs(random) % modulus);
|
||||
}
|
||||
|
||||
private String asHex(byte[] data) {
|
||||
String result = "";
|
||||
|
||||
for(byte value : data) {
|
||||
result = result + String.format("%02x", value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
throws IOException, InterruptedException
|
||||
{
|
||||
SecureRandom rng = new SecureRandom();
|
||||
FileWriter outfile = new FileWriter("signature.test", false);
|
||||
Generator gen = new Generator(rng, outfile);
|
||||
|
||||
gen.runTests(1024, 160, 500);
|
||||
gen.runTests(2048, 224, 500);
|
||||
gen.runTests(2048, 256, 250);
|
||||
gen.runTests(3072, 256, 100);
|
||||
}
|
||||
|
||||
private class Runner implements Runnable {
|
||||
private int lsize;
|
||||
private int nsize;
|
||||
private int count;
|
||||
private Generator parent;
|
||||
|
||||
public Runner(int lsize, int nsize, int count, Generator parent)
|
||||
{
|
||||
this.lsize = lsize;
|
||||
this.nsize = nsize;
|
||||
this.count = count;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
for(int i = 0; i < count; i++) {
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
private DSAParameters getParameters()
|
||||
throws IOException
|
||||
{
|
||||
DSAParameterGenerationParameters genparams =
|
||||
new DSAParameterGenerationParameters(lsize, nsize, 80, rng);
|
||||
DSAParametersGenerator gen =
|
||||
new DSAParametersGenerator(parent.appropriateDigest(nsize));
|
||||
gen.init(genparams);
|
||||
return gen.generateParameters();
|
||||
}
|
||||
|
||||
private AsymmetricCipherKeyPair getKeyPair(DSAParameters params)
|
||||
{
|
||||
DSAKeyGenerationParameters dsakeygenparams =
|
||||
new DSAKeyGenerationParameters(rng, params);
|
||||
DSAKeyPairGenerator keygen = new DSAKeyPairGenerator();
|
||||
keygen.init(dsakeygenparams);
|
||||
return keygen.generateKeyPair();
|
||||
}
|
||||
|
||||
private byte[] getMessage()
|
||||
{
|
||||
int msgsize = getRandomChoice(1024);
|
||||
byte message[] = new byte[msgsize];
|
||||
rng.nextBytes(message);
|
||||
return message;
|
||||
}
|
||||
|
||||
private byte[] runHash(byte[] msg, int digestsize)
|
||||
throws IOException
|
||||
{
|
||||
Digest digestfn = appropriateDigest(digestsize);
|
||||
digestfn.update(msg, 0, msg.length);
|
||||
byte result[] = new byte[digestfn.getDigestSize()];
|
||||
digestfn.doFinal(result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void runTest()
|
||||
{
|
||||
try {
|
||||
DSAParameters params = getParameters();
|
||||
AsymmetricCipherKeyPair kp = getKeyPair(params);
|
||||
DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic();
|
||||
DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate();
|
||||
|
||||
byte message[] = getMessage();
|
||||
int digestsize = randomDigestSize();
|
||||
byte hash[] = runHash(message, digestsize);
|
||||
|
||||
Digest msgdigest = appropriateDigest(digestsize);
|
||||
HMacDSAKCalculator kgen = new HMacDSAKCalculator(msgdigest);
|
||||
DSASigner signer = new DSASigner(kgen);
|
||||
signer.init(true, priv);
|
||||
BigInteger rs[] = signer.generateSignature(hash);
|
||||
parent.output(params, kp, digestsize, message, rs);
|
||||
} catch(IOException exc) {
|
||||
System.out.println("EXCEPTION!");
|
||||
run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12132
tests/dsa/signature.test
12132
tests/dsa/signature.test
File diff suppressed because it is too large
Load Diff
@@ -1,318 +0,0 @@
|
||||
// Just because I always forget Java compilation:
|
||||
// javac Generator.java -cp bcprov-ext-jdk15on-159.jar
|
||||
// java -cp "bcprov-ext-jdk15on-159.jar:." Generator
|
||||
// Also, go here:
|
||||
// https://www.bouncycastle.org/latest_releases.html
|
||||
//
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.lang.InterruptedException;
|
||||
import java.lang.Math;
|
||||
import java.lang.Thread;
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import org.bouncycastle.asn1.nist.NISTNamedCurves;
|
||||
import org.bouncycastle.asn1.x9.X9ECParameters;
|
||||
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
|
||||
import org.bouncycastle.crypto.Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA1Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA224Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA256Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA384Digest;
|
||||
import org.bouncycastle.crypto.digests.SHA512Digest;
|
||||
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
|
||||
import org.bouncycastle.crypto.params.ECDomainParameters;
|
||||
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
|
||||
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
|
||||
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
|
||||
import org.bouncycastle.crypto.signers.ECDSASigner;
|
||||
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
|
||||
import org.bouncycastle.math.ec.ECAlgorithms;
|
||||
import org.bouncycastle.math.ec.ECPoint;
|
||||
|
||||
class Generator {
|
||||
final static int COUNT = 500;
|
||||
|
||||
public static void main(String[] args)
|
||||
throws IOException, InterruptedException
|
||||
{
|
||||
new Generator().run();
|
||||
}
|
||||
|
||||
public Generator() { }
|
||||
|
||||
public void run()
|
||||
throws IOException, InterruptedException
|
||||
{
|
||||
OutFiles outfiles = new OutFiles();
|
||||
String[] curves = { "P-192", "P-224", "P-256", "P-384", "P-521" };
|
||||
ArrayList<Thread> threads = new ArrayList<Thread>();
|
||||
|
||||
System.out.print("Generating: ");
|
||||
for(String curve : curves) {
|
||||
X9ECParameters params = NISTNamedCurves.getByName(curve);
|
||||
ECDomainParameters dp = new ECDomainParameters(params.getCurve(),
|
||||
params.getG(),
|
||||
params.getN());
|
||||
Runner runner = new Runner(outfiles, dp);
|
||||
Thread thread = new Thread(runner);
|
||||
thread.start();
|
||||
threads.add(thread);
|
||||
}
|
||||
|
||||
for(Thread thread: threads) {
|
||||
thread.join();
|
||||
}
|
||||
System.out.println(" done.");
|
||||
}
|
||||
|
||||
public class OutFiles {
|
||||
public FileWriter negate;
|
||||
public FileWriter dble;
|
||||
public FileWriter add;
|
||||
public FileWriter mul;
|
||||
public FileWriter add2mul;
|
||||
public FileWriter sig;
|
||||
|
||||
public OutFiles()
|
||||
{
|
||||
try {
|
||||
negate = new FileWriter("ec_negate.test", false);
|
||||
dble = new FileWriter("ec_dble.test", false);
|
||||
add = new FileWriter("ec_add.test", false);
|
||||
mul = new FileWriter("ec_mul.test", false);
|
||||
add2mul = new FileWriter("ec_add2mul.test", false);
|
||||
sig = new FileWriter("signature.test", false);
|
||||
} catch(IOException e) {
|
||||
System.out.println("Blech: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void dump(FileWriter file, Map<String,String> x) {
|
||||
try {
|
||||
for(Map.Entry<String,String> entry : x.entrySet()) {
|
||||
file.write(entry.getKey());
|
||||
file.write(": ");
|
||||
file.write(entry.getValue());
|
||||
file.write("\n");
|
||||
file.flush();
|
||||
|
||||
if(file == negate) { System.out.print("N"); };
|
||||
if(file == dble) { System.out.print("D"); };
|
||||
if(file == add) { System.out.print("A"); };
|
||||
if(file == mul) { System.out.print("M"); };
|
||||
if(file == add2mul) { System.out.print("2"); };
|
||||
if(file == sig) { System.out.print("S"); };
|
||||
System.out.flush();
|
||||
}
|
||||
} catch(IOException e) {
|
||||
System.out.println("Argh: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Runner implements Runnable {
|
||||
private OutFiles outfiles;
|
||||
private SecureRandom rng;
|
||||
private ECDomainParameters ecparams;
|
||||
private BigInteger two;
|
||||
|
||||
public Runner(OutFiles outfiles, ECDomainParameters params) {
|
||||
this.outfiles = outfiles;
|
||||
this.ecparams = params;
|
||||
this.rng = new SecureRandom();
|
||||
this.two = BigInteger.valueOf(2);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
for(int i = 0; i < COUNT; i++) { generateNegateTests(); }
|
||||
for(int i = 0; i < COUNT; i++) { generateDoubleTests(); }
|
||||
for(int i = 0; i < COUNT; i++) { generateAddTests(); }
|
||||
for(int i = 0; i < COUNT; i++) { generateMulTests(); }
|
||||
for(int i = 0; i < COUNT; i++) { generateAdd2MulTests(); }
|
||||
for(int i = 0; i < COUNT; i++) { generateSignatureTests(); }
|
||||
}
|
||||
|
||||
public void generateNegateTests() {
|
||||
ECPoint p = getPoint();
|
||||
ECPoint n = p.negate().normalize();
|
||||
HashMap<String,String> m = new HashMap<String,String>();
|
||||
|
||||
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||
m.put("x", p.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("y", p.getAffineYCoord().toBigInteger().toString(16));
|
||||
m.put("a", n.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("b", n.getAffineYCoord().toBigInteger().toString(16));
|
||||
outfiles.dump(outfiles.negate, m);
|
||||
}
|
||||
|
||||
public void generateDoubleTests() {
|
||||
ECPoint p = getPoint();
|
||||
ECPoint n = p.twice().normalize();
|
||||
HashMap<String,String> m = new HashMap<String,String>();
|
||||
|
||||
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||
m.put("x", p.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("y", p.getAffineYCoord().toBigInteger().toString(16));
|
||||
m.put("a", n.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("b", n.getAffineYCoord().toBigInteger().toString(16));
|
||||
outfiles.dump(outfiles.dble, m);
|
||||
}
|
||||
|
||||
public void generateAddTests() {
|
||||
ECPoint p1 = getPoint();
|
||||
ECPoint p2 = getPoint();
|
||||
ECPoint q = p1.add(p2).normalize();
|
||||
HashMap<String,String> m = new HashMap<String,String>();
|
||||
|
||||
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||
m.put("x", p1.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("y", p1.getAffineYCoord().toBigInteger().toString(16));
|
||||
m.put("q", p2.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("r", p2.getAffineYCoord().toBigInteger().toString(16));
|
||||
m.put("a", q.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("b", q.getAffineYCoord().toBigInteger().toString(16));
|
||||
outfiles.dump(outfiles.add, m);
|
||||
}
|
||||
|
||||
public void generateMulTests() {
|
||||
ECPoint p = getPoint();
|
||||
BigInteger k = getConstant();
|
||||
ECPoint q = p.multiply(k).normalize();
|
||||
HashMap<String,String> m = new HashMap<String,String>();
|
||||
|
||||
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||
m.put("x", p.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("y", p.getAffineYCoord().toBigInteger().toString(16));
|
||||
m.put("k", k.toString(16));
|
||||
m.put("a", q.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("b", q.getAffineYCoord().toBigInteger().toString(16));
|
||||
outfiles.dump(outfiles.mul, m);
|
||||
}
|
||||
|
||||
public void generateAdd2MulTests() {
|
||||
ECPoint p = getPoint();
|
||||
BigInteger a = getConstant();
|
||||
ECPoint q = getPoint();
|
||||
BigInteger b = getConstant();
|
||||
ECPoint r = ECAlgorithms.sumOfTwoMultiplies(p,a,q,b).normalize();
|
||||
HashMap<String,String> m = new HashMap<String,String>();
|
||||
|
||||
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||
m.put("x", p.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("y", p.getAffineYCoord().toBigInteger().toString(16));
|
||||
m.put("a", a.toString(16));
|
||||
m.put("q", q.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("r", q.getAffineYCoord().toBigInteger().toString(16));
|
||||
m.put("b", b.toString(16));
|
||||
m.put("s", r.getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("t", r.getAffineYCoord().toBigInteger().toString(16));
|
||||
outfiles.dump(outfiles.add2mul, m);
|
||||
}
|
||||
|
||||
public void generateSignatureTests() {
|
||||
AsymmetricCipherKeyPair kp = getKeyPair();
|
||||
ECPublicKeyParameters pub = (ECPublicKeyParameters)kp.getPublic();
|
||||
ECPrivateKeyParameters priv = (ECPrivateKeyParameters)kp.getPrivate();
|
||||
byte message[] = getMessage();
|
||||
int digestsize = getDigestSize();
|
||||
byte hash[] = runHash(message, digestsize);
|
||||
Digest msgdigest = getHash(digestsize);
|
||||
HMacDSAKCalculator kgen = new HMacDSAKCalculator(msgdigest);
|
||||
ECDSASigner signer = new ECDSASigner(kgen);
|
||||
signer.init(true, priv);
|
||||
BigInteger rs[] = signer.generateSignature(hash);
|
||||
HashMap<String,String> m = new HashMap<String,String>();
|
||||
|
||||
m.put("c", Integer.toString(ecparams.getN().bitLength()));
|
||||
m.put("x", pub.getQ().getAffineXCoord().toBigInteger().toString(16));
|
||||
m.put("y", pub.getQ().getAffineYCoord().toBigInteger().toString(16));
|
||||
m.put("d", priv.getD().toString(16));
|
||||
m.put("h", Integer.toString(digestsize));
|
||||
m.put("m", asHex(message));
|
||||
m.put("r", rs[0].toString(16));
|
||||
m.put("s", rs[1].toString(16));
|
||||
outfiles.dump(outfiles.sig, m);
|
||||
}
|
||||
|
||||
private byte[] runHash(byte[] msg, int size) {
|
||||
Digest digestfn = getHash(size);
|
||||
digestfn.update(msg, 0, msg.length);
|
||||
byte result[] = new byte[digestfn.getDigestSize()];
|
||||
digestfn.doFinal(result, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
private AsymmetricCipherKeyPair getKeyPair() {
|
||||
ECKeyGenerationParameters params =
|
||||
new ECKeyGenerationParameters(ecparams, rng);
|
||||
ECKeyPairGenerator keygen = new ECKeyPairGenerator();
|
||||
keygen.init(params);
|
||||
return keygen.generateKeyPair();
|
||||
}
|
||||
|
||||
private byte[] getMessage() {
|
||||
int msgsize = rng.nextInt(1024);
|
||||
byte message[] = new byte[msgsize];
|
||||
rng.nextBytes(message);
|
||||
return message;
|
||||
}
|
||||
|
||||
private ECPoint getPoint() {
|
||||
BigInteger k = getConstant();
|
||||
return ecparams.getG().multiply(k).normalize();
|
||||
}
|
||||
|
||||
private BigInteger getConstant() {
|
||||
BigInteger n = ecparams.getN();
|
||||
int nBitLength = n.bitLength();
|
||||
|
||||
for(;;) {
|
||||
BigInteger d = new BigInteger(nBitLength, rng);
|
||||
|
||||
if(d.compareTo(two) < 0 || (d.compareTo(n) >= 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
private int getDigestSize() {
|
||||
switch(rng.nextInt(5)) {
|
||||
case 0: return 1;
|
||||
case 1: return 224;
|
||||
case 2: return 256;
|
||||
case 3: return 384;
|
||||
case 4: return 512;
|
||||
default:
|
||||
return 999;
|
||||
}
|
||||
}
|
||||
|
||||
private Digest getHash(int nsize) {
|
||||
switch(nsize) {
|
||||
case 1: return new SHA1Digest();
|
||||
case 224: return new SHA1Digest();
|
||||
case 256: return new SHA1Digest();
|
||||
case 384: return new SHA1Digest();
|
||||
case 512: return new SHA1Digest();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String asHex(byte[] data) {
|
||||
String result = "";
|
||||
for(byte value : data) {
|
||||
result = result + String.format("%02x", value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
17500
tests/ecdsa/ec_add.test
17500
tests/ecdsa/ec_add.test
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
12500
tests/ecdsa/ec_dble.test
12500
tests/ecdsa/ec_dble.test
File diff suppressed because it is too large
Load Diff
15000
tests/ecdsa/ec_mul.test
15000
tests/ecdsa/ec_mul.test
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,216 +0,0 @@
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
import Control.Monad
|
||||
import Data.Bits
|
||||
import Data.List
|
||||
import qualified Data.Map.Strict as Map
|
||||
import GHC.Integer.GMP.Internals
|
||||
import Numeric
|
||||
import System.IO
|
||||
import System.Random
|
||||
import Debug.Trace
|
||||
|
||||
type Generator a = StdGen -> a -> (Maybe [(String, Integer)], a, StdGen)
|
||||
|
||||
iterations :: Int
|
||||
iterations = 5000
|
||||
|
||||
maxSize :: Int
|
||||
maxSize = 8
|
||||
|
||||
randomVal :: (Integer -> Bool) -> StdGen -> (Integer, StdGen)
|
||||
randomVal filter g =
|
||||
let (mySize, g') = randomR (1, maxSize) g
|
||||
(possible, g'') = go g' mySize
|
||||
in if filter possible
|
||||
then (possible, g'')
|
||||
else randomVal filter g''
|
||||
where
|
||||
go rng 0 = (0, rng)
|
||||
go rng i =
|
||||
let (other, rng') = go rng (i - 1)
|
||||
(self, rng'') = random rng'
|
||||
in ((other `shiftL` 64) + self, rng'')
|
||||
|
||||
buildBasicGenerator :: (Integer -> Bool) ->
|
||||
(Integer -> Integer -> Maybe Integer) ->
|
||||
Generator ()
|
||||
buildBasicGenerator filter f g () =
|
||||
let (x, g') = randomVal filter g
|
||||
(y, g'') = randomVal filter g'
|
||||
in case f x y of
|
||||
Nothing ->
|
||||
(Nothing, (), g'')
|
||||
Just z ->
|
||||
(Just [("x", x), ("y", y), ("z", z)], (), g'')
|
||||
|
||||
buildBasicLimitingGenerator :: (Integer -> Bool) ->
|
||||
(Integer -> Integer -> Maybe Integer) ->
|
||||
Generator (Map.Map Integer Int)
|
||||
buildBasicLimitingGenerator filter f g m =
|
||||
let (x, g') = randomVal filter g
|
||||
(y, g'') = randomVal filter g'
|
||||
in case f x y of
|
||||
Nothing -> (Nothing, m, g'')
|
||||
Just z ->
|
||||
case Map.lookup z m of
|
||||
Nothing ->
|
||||
(Just [("x",x),("y",y),("z",z)], Map.insert z 1 m, g'')
|
||||
Just c | c >= 100 ->
|
||||
(Nothing, m, g'')
|
||||
Just c ->
|
||||
(Just [("x",x),("y",y),("z",z)], Map.insert z (c + 1) m, g'')
|
||||
|
||||
buildBasicAccGenerator :: (Integer -> Bool) ->
|
||||
(Integer -> Integer -> a -> Maybe (Integer, a)) ->
|
||||
Generator a
|
||||
buildBasicAccGenerator filter f g acc =
|
||||
let (x, g') = randomVal filter g
|
||||
(y, g'') = randomVal filter g'
|
||||
in case f x y acc of
|
||||
Nothing ->
|
||||
(Nothing, acc, g'')
|
||||
Just (z, acc') ->
|
||||
(Just [("x", x), ("y", y), ("z", z)], acc', g'')
|
||||
|
||||
runGenerator :: forall a. StdGen -> String -> a -> Generator a -> IO StdGen
|
||||
runGenerator g filename initVal generator =
|
||||
withFile (filename ++ ".tests") WriteMode $ \ hndl ->
|
||||
do putStrLn ("Generating " ++ filename ++ ".tests")
|
||||
go hndl g initVal iterations
|
||||
where
|
||||
go :: Handle -> StdGen -> a -> Int -> IO StdGen
|
||||
go _ g _ 0 = return g
|
||||
go hndl g acc iterations =
|
||||
case generator g acc of
|
||||
(Nothing, acc', g') ->
|
||||
go hndl g' acc' iterations
|
||||
(Just res, acc', g') ->
|
||||
do let sorted = sort res
|
||||
forM_ sorted $ \ (key, val) ->
|
||||
do let neg = if val < 0 then "-" else ""
|
||||
val' = abs val
|
||||
hPutStrLn hndl (key ++ ": " ++ neg ++ showHex val' "")
|
||||
go hndl g' acc' (iterations - 1)
|
||||
|
||||
main :: IO ()
|
||||
main =
|
||||
do g0 <- newStdGen
|
||||
g1 <- runGenerator g0 "unsigned_add" () $
|
||||
buildBasicGenerator (>= 0) $ \ a b -> Just (a + b)
|
||||
g2 <- runGenerator g1 "signed_add" () $
|
||||
buildBasicGenerator (const True) $ \ a b -> Just (a + b)
|
||||
g3 <- runGenerator g2 "unsigned_sub" () $
|
||||
buildBasicGenerator (>= 0) $ \ a b ->
|
||||
if a >= b then Just (a - b) else Nothing
|
||||
g4 <- runGenerator g3 "signed_sub" () $
|
||||
buildBasicGenerator (const True) $ \ a b -> Just (a - b)
|
||||
g5 <- runGenerator g4 "unsigned_mul" () $
|
||||
buildBasicGenerator (>= 0) $ \ a b -> Just (a * b)
|
||||
g6 <- runGenerator g5 "signed_mul" () $
|
||||
buildBasicGenerator (const True) $ \ a b -> Just (a * b)
|
||||
g7 <- runGenerator g6 "unsigned_div" Map.empty $
|
||||
buildBasicLimitingGenerator (>= 0) $ \ a b ->
|
||||
if b == 0 then Nothing else Just (a `div` b)
|
||||
g8 <- runGenerator g7 "signed_div" Map.empty $
|
||||
buildBasicLimitingGenerator (const True) $ \ a b ->
|
||||
if b == 0 then Nothing else Just (a `div` b)
|
||||
g7 <- runGenerator g6 "unsigned_mod" 0 $
|
||||
buildBasicAccGenerator (>= 0) $ \ a b i ->
|
||||
case a `mod` b of
|
||||
_ | b == 0 -> Nothing
|
||||
x | (a == x) && (i == 100) -> Nothing
|
||||
x | a == x -> Just (x, i + 1)
|
||||
x -> Just (x, i)
|
||||
g8 <- runGenerator g7 "signed_mod" 0 $
|
||||
buildBasicAccGenerator (const True) $ \ a b i ->
|
||||
case a `mod` b of
|
||||
_ | b == 0 -> Nothing
|
||||
x | (a == x) && (i == 100) -> Nothing
|
||||
x | a == x -> Just (x, i + 1)
|
||||
x -> Just (x, i)
|
||||
g9 <- runGenerator g8 "modexp" () $ \ g () ->
|
||||
let (a, g') = randomVal (>= 0) g
|
||||
(b, g'') = randomVal (>= 0) g'
|
||||
(m, g''') = randomVal (>= 0) g''
|
||||
z = powModInteger a b m
|
||||
res = [("a",a),("b",b),("m",m),("z",z)]
|
||||
in if m == 0
|
||||
then (Nothing, (), g''')
|
||||
else (Just res, (), g''')
|
||||
g10<- runGenerator g9 "barrett" () $ \ g () ->
|
||||
let (m, g') = randomVal (>= 0) g
|
||||
(v, g'') = randomVal (>= 0) g'
|
||||
barrett = barrett_u m
|
||||
vk = computeK v
|
||||
in if vk > (2 * (bk barrett))
|
||||
then (Nothing, (), g'')
|
||||
else let me = reduce v barrett
|
||||
standard = v `mod` m
|
||||
res = [("m", m), ("v", v), ("r", me),
|
||||
("u", bu barrett), ("k", fromIntegral (bk barrett))]
|
||||
in if me /= standard
|
||||
then error "Barrett broken"
|
||||
else (Just res, (), g'')
|
||||
g11<- runGenerator g10 "fastmodexp" () $ \ g () ->
|
||||
let (a, g') = randomVal (>= 0) g
|
||||
(b, g'') = randomVal (>= 0) g'
|
||||
(m, g''') = randomVal (>= 0) g'
|
||||
z = powModInteger a b m
|
||||
barrett = barrett_u m
|
||||
ak = computeK a
|
||||
in if ak > bk barrett
|
||||
then (Nothing, (), g''')
|
||||
else let res = [("a", a), ("b", b), ("z", z),
|
||||
("m", m), ("u", bu barrett),
|
||||
("k", fromIntegral (bk barrett))]
|
||||
in (Just res, (), g''')
|
||||
_ <- runGenerator g11 "modinv" Map.empty $
|
||||
buildBasicLimitingGenerator (>= 0) $ \ a b ->
|
||||
let res == recipModInteger a b
|
||||
if b == 0 then Nothing else Just (recipModInteger a b)
|
||||
return ()
|
||||
|
||||
-- Implement Barrett reduction using incredibly simplistic implementations, to
|
||||
-- be sure we got it right.
|
||||
--
|
||||
b :: Integer
|
||||
b = 2 ^ 64
|
||||
|
||||
computeK :: Integer -> Int
|
||||
computeK v = go 0 1
|
||||
where
|
||||
go k acc
|
||||
| v < acc = k
|
||||
| otherwise = go (k + 1) (acc * b)
|
||||
|
||||
data Barrett = Barrett { bm :: Integer, bu :: Integer, bk :: Int }
|
||||
deriving (Show)
|
||||
|
||||
barrett_u :: Integer -> Barrett
|
||||
barrett_u x = Barrett {
|
||||
bm = x,
|
||||
bu = (b ^ (2 * k)) `div` x,
|
||||
bk = k
|
||||
}
|
||||
where k = computeK x
|
||||
|
||||
reduce :: Integer -> Barrett -> Integer
|
||||
reduce x barrett = result
|
||||
where
|
||||
k = bk barrett
|
||||
u = bu barrett
|
||||
m = bm barrett
|
||||
--
|
||||
q1 = x `div` (b ^ (k - 1))
|
||||
q2 = q1 * u
|
||||
q3 = q2 `div` (b ^ (k + 1))
|
||||
r1 = x `mod` (b ^ (k + 1))
|
||||
r2 = (q3 * m) `mod` (b ^ (k + 1))
|
||||
r = r1 - r2
|
||||
r' = if r < 0 then r + (b ^ (k + 1)) else r
|
||||
result = minimize r' m
|
||||
|
||||
minimize :: Integer -> Integer -> Integer
|
||||
minimize r m | r < 0 = error "BLECH"
|
||||
| r >= m = minimize (r - m) m
|
||||
| otherwise = r
|
||||
25000
tests/math/barrett.tests
25000
tests/math/barrett.tests
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
20000
tests/math/modexp.tests
20000
tests/math/modexp.tests
File diff suppressed because it is too large
Load Diff
15000
tests/math/modinv.tests
15000
tests/math/modinv.tests
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,214 +0,0 @@
|
||||
{-# LANGUAGE ScopedTypeVariables #-}
|
||||
import Control.Monad
|
||||
import Codec.Crypto.RSA.Pure
|
||||
import Control.Concurrent
|
||||
import Crypto.Random.DRBG
|
||||
import Data.Bits
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Char8 as BSC
|
||||
import qualified Data.ByteString.Lazy as BSL
|
||||
import Data.Char
|
||||
import Data.List
|
||||
import qualified Data.Map.Strict as Map
|
||||
import GHC.Integer.GMP.Internals
|
||||
import Numeric
|
||||
import System.IO
|
||||
import System.ProgressBar
|
||||
import System.Random
|
||||
import Debug.Trace
|
||||
|
||||
keySizes :: [Int]
|
||||
keySizes = [512,1024,2048,3072,4096,7680,8192,15360]
|
||||
|
||||
keyIterations :: [Int]
|
||||
keyIterations = replicate 500 512 ++
|
||||
replicate 500 1024 ++
|
||||
replicate 250 2048 ++
|
||||
replicate 125 3072 ++
|
||||
replicate 50 4096 ++
|
||||
replicate 5 7680 ++
|
||||
replicate 2 8192 ++
|
||||
replicate 1 15360
|
||||
|
||||
randomByteString :: CryptoRandomGen g => g -> (BS.ByteString, g)
|
||||
randomByteString g =
|
||||
let Right (bs, g') = genBytes 2 g
|
||||
[h,l] = BS.unpack bs
|
||||
x = (fromIntegral h `shiftL` 8) + (fromIntegral l)
|
||||
Right (res, g'') = genBytes (x `mod` 1024) g'
|
||||
in (res, g'')
|
||||
|
||||
randomLabel :: CryptoRandomGen g => g -> (BS.ByteString, g)
|
||||
randomLabel g =
|
||||
let Right (ls, g') = genBytes 1 g
|
||||
[l8] = BS.unpack ls
|
||||
(letters, g'') = go g' (l8 `mod` 24)
|
||||
in (BSC.pack letters, g'')
|
||||
where
|
||||
goodChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ++
|
||||
"abcdefghijklmnopqrstuvwxyz" ++
|
||||
"0123456789 .,/?'\";:[{]}\\|-_=+" ++
|
||||
"`~!@#$%^&*()"
|
||||
lenGoods = fromIntegral (length goodChars)
|
||||
--
|
||||
go g 0 = ("", g)
|
||||
go g x =
|
||||
let Right (bs, g') = genBytes 1 g
|
||||
[x] = BS.unpack bs
|
||||
idx = fromIntegral (x `mod` lenGoods)
|
||||
(rest, g'') = go g' (x - 1)
|
||||
in ((goodChars !! idx) : rest, g'')
|
||||
|
||||
randomHash :: CryptoRandomGen g => g -> ((HashInfo, String), g)
|
||||
randomHash g =
|
||||
randomElement g [(hashSHA1, "1"),
|
||||
(hashSHA224, "224"),
|
||||
(hashSHA256, "256"),
|
||||
(hashSHA384, "384"),
|
||||
(hashSHA512, "512")]
|
||||
|
||||
showBinary :: BS.ByteString -> String
|
||||
showBinary v = go v
|
||||
where
|
||||
go bstr =
|
||||
case BS.uncons bstr of
|
||||
Nothing ->
|
||||
""
|
||||
Just (x, rest) ->
|
||||
let high = showHex (x `shiftR` 4) ""
|
||||
low = showHex (x .&. 0xF) ""
|
||||
in high ++ low ++ go rest
|
||||
|
||||
dump :: Handle -> [(String,String)] -> IO ()
|
||||
dump hndl = mapM_ writeItem
|
||||
where
|
||||
writeItem (name, value) =
|
||||
do hPutStr hndl name
|
||||
hPutStr hndl ": "
|
||||
hPutStrLn hndl value
|
||||
|
||||
mkProgress x y = Progress (fromIntegral x) (fromIntegral y)
|
||||
|
||||
runSignatureGenerator :: Chan Int -> Chan [(String,String)] -> IO ()
|
||||
runSignatureGenerator inputs outputs =
|
||||
do rng0 :: GenBuffered SystemRandom <- newGenIO
|
||||
go Nothing rng0
|
||||
where
|
||||
go Nothing rng0 =
|
||||
do keySize <- readChan inputs
|
||||
go (Just keySize) rng0
|
||||
go (Just keySize) g0 =
|
||||
do unless (keySize `elem` keySizes) $
|
||||
fail ("Bad key size: " ++ show keySize)
|
||||
let Right (public, private, g1) = generateKeyPair g0 keySize
|
||||
unless (private_d private `shiftR` keySize == 0) $
|
||||
fail ("Bad private key size.")
|
||||
unless (public_n public `shiftR` keySize == 0) $
|
||||
fail ("Bad private key size.")
|
||||
let (message, g2) = randomByteString g1
|
||||
let ((hash, hashname), g3) = randomHash g2
|
||||
case rsassa_pkcs1_v1_5_sign hash private (BSL.fromStrict message) of
|
||||
Left _ ->
|
||||
go (Just keySize) g3
|
||||
Right sig ->
|
||||
case rsassa_pkcs1_v1_5_verify hash public (BSL.fromStrict message) sig of
|
||||
Left err ->
|
||||
fail ("RSA Verification error: " ++ show err)
|
||||
Right False ->
|
||||
fail ("RSA verification failed?!")
|
||||
Right True ->
|
||||
do writeChan outputs [("d", showHex (private_d private) ""),
|
||||
("n", showHex (public_n public) ""),
|
||||
("h", hashname),
|
||||
("k", showHex keySize ""),
|
||||
("l", showHex (BS.length message) ""),
|
||||
("m", showBinary message),
|
||||
("s", showBinary (BSL.toStrict sig))]
|
||||
go Nothing g3
|
||||
|
||||
runEncryptionGenerator :: Chan Int -> Chan [(String,String)] -> IO ()
|
||||
runEncryptionGenerator inputs outputs =
|
||||
do rng0 :: GenBuffered SystemRandom <- newGenIO
|
||||
go Nothing rng0
|
||||
where
|
||||
go Nothing rng0 =
|
||||
do keySize <- readChan inputs
|
||||
go (Just keySize) rng0
|
||||
go (Just keySize) g0 =
|
||||
do unless (keySize `elem` keySizes) $
|
||||
fail ("Bad key size: " ++ show keySize)
|
||||
let Right (public, private, g1) = generateKeyPair g0 keySize
|
||||
let (message, g2) = randomByteString g1
|
||||
let (label, g3) = randomLabel g2
|
||||
let ((hashinfo, hashname), g4) = randomHash g3
|
||||
let hash = hashFunction hashinfo
|
||||
let mgf1 = generateMGF1 hash
|
||||
let msg = BSL.fromStrict message
|
||||
lbl = BSL.fromStrict label
|
||||
case encryptOAEP g4 hash mgf1 lbl public msg of
|
||||
Left _ ->
|
||||
go (Just keySize) g4
|
||||
Right (c, g5) ->
|
||||
do writeChan outputs [("d", showHex (private_d private) ""),
|
||||
("n", showHex (public_n public) ""),
|
||||
("h", hashname),
|
||||
("l", showBinary label),
|
||||
("m", showBinary message),
|
||||
("c", showBinary (BSL.toStrict c))]
|
||||
go Nothing g5
|
||||
|
||||
writeData :: Chan [(String,String)] -> Int -> (Progress -> IO ()) ->
|
||||
Handle ->
|
||||
IO ()
|
||||
writeData outputChan countInt progressBar hndl = go 0
|
||||
where
|
||||
count = fromIntegral countInt
|
||||
go x | x == count = return ()
|
||||
| otherwise = do output <- readChan outputChan
|
||||
dump hndl output
|
||||
hFlush hndl
|
||||
progressBar (Progress (x + 1) count)
|
||||
go (x + 1)
|
||||
|
||||
main :: IO ()
|
||||
main =
|
||||
do sizeChan <- newChan
|
||||
outputChan <- newChan
|
||||
let count = length keyIterations
|
||||
numThreads <- getNumCapabilities
|
||||
--
|
||||
unless (all (`elem` keySizes) keyIterations) $
|
||||
fail "System setup failure."
|
||||
--
|
||||
sigthrs <- replicateM numThreads $
|
||||
forkIO $ runSignatureGenerator sizeChan outputChan
|
||||
let bar = autoProgressBar (msg "Generating signature tests") percentage 60
|
||||
writeList2Chan sizeChan keyIterations
|
||||
g1 <- withFile "signature.test" WriteMode $
|
||||
writeData outputChan count bar
|
||||
mapM_ killThread sigthrs
|
||||
--
|
||||
encthrs <- replicateM numThreads $
|
||||
forkIO $ runEncryptionGenerator sizeChan outputChan
|
||||
let bar = autoProgressBar (msg "Generating encryption tests") percentage 60
|
||||
writeList2Chan sizeChan (take 1000 keyIterations)
|
||||
g2 <- withFile "encryption.test" WriteMode $
|
||||
writeData outputChan 1000 bar
|
||||
mapM_ killThread encthrs
|
||||
--
|
||||
replicateM_ numThreads $
|
||||
void $ forkIO $ runEncryptionGenerator sizeChan outputChan
|
||||
let bar = autoProgressBar (msg "Generating encryption tests") percentage 60
|
||||
writeList2Chan sizeChan (drop 1000 keyIterations)
|
||||
let i = length keyIterations - 1
|
||||
g2 <- withFile "encryption.ext.test" WriteMode $
|
||||
writeData outputChan (count - 1000) bar
|
||||
--
|
||||
return ()
|
||||
|
||||
randomElement :: CryptoRandomGen g => g -> [a] -> (a, g)
|
||||
randomElement g xs =
|
||||
let Right (bs, g') = genBytes 1 g
|
||||
x = BS.head bs
|
||||
idx = fromIntegral x `mod` length xs
|
||||
in (xs !! idx, g')
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
10031
tests/rsa/signature.test
10031
tests/rsa/signature.test
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user