mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-07-26 20:22:51 +02:00
Benchmarks, internal P-384, some other stuff.
This commit is contained in:
parent
a723403fe9
commit
1fad0039fc
15 changed files with 1373 additions and 318 deletions
|
@ -1 +1 @@
|
||||||
|
fn main() {}
|
||||||
|
|
|
@ -1,26 +1,30 @@
|
||||||
[package]
|
[package]
|
||||||
name = "zerotier-core-crypto"
|
authors = ["ZeroTier, Inc. <contact@zerotier.com>", "Adam Ierymenko <adam.ierymenko@zerotier.com>"]
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MPL-2.0"
|
license = "MPL-2.0"
|
||||||
authors = ["ZeroTier, Inc. <contact@zerotier.com>", "Adam Ierymenko <adam.ierymenko@zerotier.com>"]
|
name = "zerotier-core-crypto"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand_core = "0.5.1"
|
ed25519-dalek = {version = "1.0.1", features = ["std", "u64_backend"], default-features = false}
|
||||||
rand_core_062 = { package = "rand_core", version = "0.6.2" }
|
|
||||||
x25519-dalek = { version = "1.2.0", features = ["std", "u64_backend"], default-features = false }
|
|
||||||
ed25519-dalek = { version = "1.0.1", features = ["std", "u64_backend"], default-features = false }
|
|
||||||
subtle = "2.4.1"
|
|
||||||
openssl = { version = "^0", features = [], default-features = false }
|
|
||||||
lazy_static = "^1"
|
|
||||||
foreign-types = "0.3.1"
|
foreign-types = "0.3.1"
|
||||||
poly1305 = { version = "0.7.2", features = [], default-features = false }
|
lazy_static = "^1"
|
||||||
parking_lot = { version = "^0", features = [], default-features = false }
|
openssl = {version = "^0", features = [], default-features = false}
|
||||||
pqc_kyber = { path = "../third_party/kyber", features = ["kyber512", "reference"], default-features = false }
|
parking_lot = {version = "^0", features = [], default-features = false}
|
||||||
|
poly1305 = {version = "0.7.2", features = [], default-features = false}
|
||||||
|
pqc_kyber = {path = "../third_party/kyber", features = ["kyber512", "reference"], default-features = false}
|
||||||
|
rand_core = "0.5.1"
|
||||||
|
rand_core_062 = {package = "rand_core", version = "0.6.2"}
|
||||||
|
subtle = "2.4.1"
|
||||||
|
x25519-dalek = {version = "1.2.0", features = ["std", "u64_backend"], default-features = false}
|
||||||
|
|
||||||
[target."cfg(not(any(target_os = \"macos\", target_os = \"ios\")))".dependencies]
|
[target."cfg(not(any(target_os = \"macos\", target_os = \"ios\")))".dependencies]
|
||||||
openssl = "^0"
|
openssl = "^0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
quickcheck = "1.0.3"
|
criterion = "0.3"
|
||||||
sha2 = "^0"
|
sha2 = "^0"
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
harness = false
|
||||||
|
name = "benchmark_crypto"
|
||||||
|
|
31
core-crypto/benches/benchmark_crypto.rs
Normal file
31
core-crypto/benches/benchmark_crypto.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
use criterion::{criterion_group, criterion_main, Criterion};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use zerotier_core_crypto::p384::*;
|
||||||
|
use zerotier_core_crypto::random;
|
||||||
|
use zerotier_core_crypto::x25519::*;
|
||||||
|
|
||||||
|
pub fn criterion_benchmark(c: &mut Criterion) {
|
||||||
|
let p384_a = P384KeyPair::generate();
|
||||||
|
let p384_b = P384KeyPair::generate();
|
||||||
|
|
||||||
|
let kyber_a = pqc_kyber::keypair(&mut random::SecureRandom::default());
|
||||||
|
let kyber_encap = pqc_kyber::encapsulate(&kyber_a.public, &mut random::SecureRandom::default()).unwrap();
|
||||||
|
|
||||||
|
let x25519_a = X25519KeyPair::generate();
|
||||||
|
let x25519_b = X25519KeyPair::generate();
|
||||||
|
let x25519_b_pub = x25519_b.public_bytes();
|
||||||
|
|
||||||
|
let mut group = c.benchmark_group("cryptography");
|
||||||
|
group.measurement_time(Duration::new(10, 0));
|
||||||
|
|
||||||
|
group.bench_function("ecdhp384", |b| b.iter(|| p384_a.agree(p384_b.public_key()).expect("ecdhp384 failed")));
|
||||||
|
group.bench_function("ecdhx25519", |b| b.iter(|| x25519_a.agree(&x25519_b_pub)));
|
||||||
|
group.bench_function("kyber_encapsulate", |b| b.iter(|| pqc_kyber::encapsulate(&kyber_a.public, &mut random::SecureRandom::default()).expect("kyber encapsulate failed")));
|
||||||
|
group.bench_function("kyber_decapsulate", |b| b.iter(|| pqc_kyber::decapsulate(&kyber_encap.0, &kyber_a.secret).expect("kyber decapsulate failed")));
|
||||||
|
|
||||||
|
group.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, criterion_benchmark);
|
||||||
|
criterion_main!(benches);
|
|
@ -379,3 +379,39 @@ pub use fruit_flavored::{Aes, AesGcm};
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
pub use openssl::{Aes, AesGcm};
|
pub use openssl::{Aes, AesGcm};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::AesGcm;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quick_benchmark() {
|
||||||
|
let mut buf = [0_u8; 12345];
|
||||||
|
for i in 1..12345 {
|
||||||
|
buf[i] = i as u8;
|
||||||
|
}
|
||||||
|
let iv = [1_u8; 16];
|
||||||
|
|
||||||
|
let mut c = AesGcm::new(&[1_u8; 32], true);
|
||||||
|
|
||||||
|
let benchmark_iterations: usize = 80000;
|
||||||
|
let start = SystemTime::now();
|
||||||
|
for _ in 0..benchmark_iterations {
|
||||||
|
c.init(&iv);
|
||||||
|
c.crypt_in_place(&mut buf);
|
||||||
|
}
|
||||||
|
let duration = SystemTime::now().duration_since(start).unwrap();
|
||||||
|
println!("AES-256-GCM encrypt benchmark: {} MiB/sec", (((benchmark_iterations * buf.len()) as f64) / 1048576.0) / duration.as_secs_f64());
|
||||||
|
|
||||||
|
let mut c = AesGcm::new(&[1_u8; 32], false);
|
||||||
|
|
||||||
|
let start = SystemTime::now();
|
||||||
|
for _ in 0..benchmark_iterations {
|
||||||
|
c.init(&iv);
|
||||||
|
c.crypt_in_place(&mut buf);
|
||||||
|
}
|
||||||
|
let duration = SystemTime::now().duration_since(start).unwrap();
|
||||||
|
println!("AES-256-GCM decrypt benchmark: {} MiB/sec", (((benchmark_iterations * buf.len()) as f64) / 1048576.0) / duration.as_secs_f64());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
|
#[allow(unused)]
|
||||||
mod impl_macos;
|
mod impl_macos;
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||||
|
#[allow(unused)]
|
||||||
mod impl_openssl;
|
mod impl_openssl;
|
||||||
|
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
|
@ -203,7 +205,7 @@ mod tests {
|
||||||
let _ = c.encrypt_second_pass_finish();
|
let _ = c.encrypt_second_pass_finish();
|
||||||
}
|
}
|
||||||
let duration = SystemTime::now().duration_since(start).unwrap();
|
let duration = SystemTime::now().duration_since(start).unwrap();
|
||||||
println!("Encrypt benchmark: {} MiB/sec", (((benchmark_iterations * buf.len()) as f64) / 1048576.0) / duration.as_secs_f64());
|
println!("AES-GMAC-SIV (legacy) encrypt benchmark: {} MiB/sec", (((benchmark_iterations * buf.len()) as f64) / 1048576.0) / duration.as_secs_f64());
|
||||||
let start = SystemTime::now();
|
let start = SystemTime::now();
|
||||||
for _ in 0..benchmark_iterations {
|
for _ in 0..benchmark_iterations {
|
||||||
c.reset();
|
c.reset();
|
||||||
|
@ -212,6 +214,6 @@ mod tests {
|
||||||
c.decrypt_finish();
|
c.decrypt_finish();
|
||||||
}
|
}
|
||||||
let duration = SystemTime::now().duration_since(start).unwrap();
|
let duration = SystemTime::now().duration_since(start).unwrap();
|
||||||
println!("Decrypt benchmark: {} MiB/sec", (((benchmark_iterations * buf.len()) as f64) / 1048576.0) / duration.as_secs_f64());
|
println!("AES-GMAC-SIV (legacy) decrypt benchmark: {} MiB/sec", (((benchmark_iterations * buf.len()) as f64) / 1048576.0) / duration.as_secs_f64());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,6 @@ pub mod secret;
|
||||||
pub mod varint;
|
pub mod varint;
|
||||||
pub mod x25519;
|
pub mod x25519;
|
||||||
|
|
||||||
|
mod p384_internal;
|
||||||
|
|
||||||
pub const ZEROES: [u8; 16] = [0_u8; 16];
|
pub const ZEROES: [u8; 16] = [0_u8; 16];
|
||||||
|
|
|
@ -100,8 +100,8 @@ const SESSION_ID_SIZE: usize = 6;
|
||||||
const KEY_DERIVATION_CHAIN_STARTING_SALT: [u8; 64] = [
|
const KEY_DERIVATION_CHAIN_STARTING_SALT: [u8; 64] = [
|
||||||
// macOS command line to generate:
|
// macOS command line to generate:
|
||||||
// echo -n 'Noise_IKpsk2_NISTP384+hybrid_AESGCM_SHA512' | shasum -a 512 | cut -d ' ' -f 1 | xxd -r -p | xxd -i
|
// echo -n 'Noise_IKpsk2_NISTP384+hybrid_AESGCM_SHA512' | shasum -a 512 | cut -d ' ' -f 1 | xxd -r -p | xxd -i
|
||||||
0xc7, 0x66, 0xf3, 0x71, 0xc8, 0xbc, 0xc3, 0x19, 0xc6, 0xf0, 0x2a, 0x6e, 0x5c, 0x4b, 0x3c, 0xc0, 0x83, 0x29, 0x09, 0x09, 0x14, 0x4a, 0xf0, 0xde, 0xea, 0x3d, 0xbd, 0x00, 0x4c, 0x9e, 0x01, 0xa0, 0x6e, 0xb6, 0x9b, 0x56, 0x47, 0x97, 0x86, 0x1d, 0x4e, 0x94,
|
0xc7, 0x66, 0xf3, 0x71, 0xc8, 0xbc, 0xc3, 0x19, 0xc6, 0xf0, 0x2a, 0x6e, 0x5c, 0x4b, 0x3c, 0xc0, 0x83, 0x29, 0x09, 0x09, 0x14, 0x4a, 0xf0, 0xde, 0xea, 0x3d, 0xbd, 0x00, 0x4c, 0x9e, 0x01, 0xa0, 0x6e, 0xb6, 0x9b, 0x56, 0x47, 0x97, 0x86, 0x1d, 0x4e, 0x94, 0xc5, 0xdd, 0xde, 0x4a, 0x1c, 0xc3, 0x4e,
|
||||||
0xc5, 0xdd, 0xde, 0x4a, 0x1c, 0xc3, 0x4e, 0xcc, 0x8b, 0x09, 0x3b, 0xb3, 0xc3, 0xb0, 0x03, 0xd7, 0xdf, 0x22, 0x49, 0x3f, 0xa5, 0x01,
|
0xcc, 0x8b, 0x09, 0x3b, 0xb3, 0xc3, 0xb0, 0x03, 0xd7, 0xdf, 0x22, 0x49, 0x3f, 0xa5, 0x01,
|
||||||
];
|
];
|
||||||
|
|
||||||
const KBKDF_KEY_USAGE_LABEL_HMAC: u8 = b'M';
|
const KBKDF_KEY_USAGE_LABEL_HMAC: u8 = b'M';
|
||||||
|
@ -110,7 +110,7 @@ const KBKDF_KEY_USAGE_LABEL_AES_GCM_BOB_TO_ALICE: u8 = b'B';
|
||||||
|
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// The packet was addressed to an unrecognized local session
|
/// The packet was addressed to an unrecognized local session
|
||||||
UnknownLocalSessionId(Option<SessionId>),
|
UnknownLocalSessionId(SessionId),
|
||||||
|
|
||||||
/// Packet was not well formed
|
/// Packet was not well formed
|
||||||
InvalidPacket,
|
InvalidPacket,
|
||||||
|
@ -311,18 +311,7 @@ impl<O> Session<O> {
|
||||||
if let Some(key) = state.keys[0].as_ref() {
|
if let Some(key) = state.keys[0].as_ref() {
|
||||||
if force || (key.lifetime.should_rekey(self.send_counter.current(), current_time) && state.offer.as_ref().map_or(true, |o| (current_time - o.creation_time) > OFFER_RATE_LIMIT_MS)) {
|
if force || (key.lifetime.should_rekey(self.send_counter.current(), current_time) && state.offer.as_ref().map_or(true, |o| (current_time - o.creation_time) > OFFER_RATE_LIMIT_MS)) {
|
||||||
if let Some(remote_s_public_p384) = P384PublicKey::from_bytes(&self.remote_s_public_p384) {
|
if let Some(remote_s_public_p384) = P384PublicKey::from_bytes(&self.remote_s_public_p384) {
|
||||||
if let Some((offer, psize)) = EphemeralOffer::create_alice_offer(
|
if let Some((offer, psize)) = EphemeralOffer::create_alice_offer(buffer, self.send_counter.next(), self.id, state.remote_session_id, local_s_public, &remote_s_public_p384, &self.ss, &self.outgoing_obfuscator, current_time, jedi) {
|
||||||
buffer,
|
|
||||||
self.send_counter.next(),
|
|
||||||
self.id,
|
|
||||||
state.remote_session_id,
|
|
||||||
local_s_public,
|
|
||||||
&remote_s_public_p384,
|
|
||||||
&self.ss,
|
|
||||||
&self.outgoing_obfuscator,
|
|
||||||
current_time,
|
|
||||||
jedi,
|
|
||||||
) {
|
|
||||||
let mut state = RwLockUpgradableReadGuard::upgrade(state);
|
let mut state = RwLockUpgradableReadGuard::upgrade(state);
|
||||||
let _ = state.offer.replace(offer);
|
let _ = state.offer.replace(offer);
|
||||||
return Some(&buffer[..psize]);
|
return Some(&buffer[..psize]);
|
||||||
|
@ -382,61 +371,56 @@ impl<O> Session<O> {
|
||||||
let packet_type = buffer[0];
|
let packet_type = buffer[0];
|
||||||
let local_session_id = SessionId::new_from_bytes(&buffer[1..7]);
|
let local_session_id = SessionId::new_from_bytes(&buffer[1..7]);
|
||||||
|
|
||||||
|
let session = local_session_id.and_then(|sid| session_lookup(sid));
|
||||||
|
|
||||||
debug_assert_eq!(PACKET_TYPE_DATA, 0);
|
debug_assert_eq!(PACKET_TYPE_DATA, 0);
|
||||||
debug_assert_eq!(PACKET_TYPE_NOP, 1);
|
debug_assert_eq!(PACKET_TYPE_NOP, 1);
|
||||||
if packet_type <= PACKET_TYPE_NOP {
|
if packet_type <= PACKET_TYPE_NOP {
|
||||||
if let Some(local_session_id) = local_session_id {
|
if let Some(session) = session {
|
||||||
if let Some(session) = session_lookup(local_session_id) {
|
let state = session.state.read();
|
||||||
let state = session.state.read();
|
for ki in 0..2 {
|
||||||
for ki in 0..2 {
|
if let Some(key) = state.keys[ki].as_ref() {
|
||||||
if let Some(key) = state.keys[ki].as_ref() {
|
let nonce = get_aes_gcm_nonce(buffer);
|
||||||
let nonce = get_aes_gcm_nonce(buffer);
|
let mut c = key.get_receive_cipher();
|
||||||
let mut c = key.get_receive_cipher();
|
c.init(&nonce);
|
||||||
c.init(&nonce);
|
c.crypt_in_place(&mut buffer[HEADER_SIZE..16]);
|
||||||
c.crypt_in_place(&mut buffer[HEADER_SIZE..16]);
|
let data_len = incoming_packet.len() - AES_GCM_TAG_SIZE;
|
||||||
let data_len = incoming_packet.len() - AES_GCM_TAG_SIZE;
|
c.crypt(&incoming_packet[16..data_len], &mut buffer[16..data_len]);
|
||||||
c.crypt(&incoming_packet[16..data_len], &mut buffer[16..data_len]);
|
let tag = c.finish();
|
||||||
let tag = c.finish();
|
key.return_receive_cipher(c);
|
||||||
key.return_receive_cipher(c);
|
|
||||||
|
|
||||||
if tag.eq(&incoming_packet[data_len..]) {
|
if tag.eq(&incoming_packet[data_len..]) {
|
||||||
if ki == 1 {
|
if ki == 1 {
|
||||||
// Promote next key to current key on success.
|
// Promote next key to current key on success.
|
||||||
unlikely_branch();
|
unlikely_branch();
|
||||||
drop(state);
|
drop(state);
|
||||||
let mut state = session.state.write();
|
let mut state = session.state.write();
|
||||||
state.keys[0] = state.keys[1].take();
|
state.keys[0] = state.keys[1].take();
|
||||||
}
|
}
|
||||||
|
|
||||||
if packet_type == PACKET_TYPE_DATA {
|
if packet_type == PACKET_TYPE_DATA {
|
||||||
return Ok(ReceiveResult::OkData(&buffer[HEADER_SIZE..data_len], u32::from_le_bytes(nonce[7..11].try_into().unwrap())));
|
return Ok(ReceiveResult::OkData(&buffer[HEADER_SIZE..data_len], u32::from_le_bytes(nonce[7..11].try_into().unwrap())));
|
||||||
} else {
|
} else {
|
||||||
return Ok(ReceiveResult::Ok);
|
return Ok(ReceiveResult::Ok);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(Error::FailedAuthentication);
|
|
||||||
} else {
|
|
||||||
unlikely_branch();
|
|
||||||
return Err(Error::UnknownLocalSessionId(Some(local_session_id)));
|
|
||||||
}
|
}
|
||||||
|
return Err(Error::FailedAuthentication);
|
||||||
} else {
|
} else {
|
||||||
unlikely_branch();
|
unlikely_branch();
|
||||||
return Err(Error::UnknownLocalSessionId(None));
|
if let Some(local_session_id) = local_session_id {
|
||||||
|
return Err(Error::UnknownLocalSessionId(local_session_id));
|
||||||
|
} else {
|
||||||
|
return Err(Error::InvalidPacket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unlikely_branch();
|
unlikely_branch();
|
||||||
|
|
||||||
let session = if let Some(local_session_id) = local_session_id {
|
if local_session_id.is_some() && session.is_none() {
|
||||||
let s = session_lookup(local_session_id);
|
return Err(Error::UnknownLocalSessionId(local_session_id.unwrap()));
|
||||||
if s.is_none() {
|
}
|
||||||
return Err(Error::UnknownLocalSessionId(Some(local_session_id)));
|
|
||||||
}
|
|
||||||
s
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if incoming_packet.len() > (HEADER_SIZE + P384_PUBLIC_KEY_SIZE + AES_GCM_TAG_SIZE + HMAC_SIZE) {
|
if incoming_packet.len() > (HEADER_SIZE + P384_PUBLIC_KEY_SIZE + AES_GCM_TAG_SIZE + HMAC_SIZE) {
|
||||||
incoming_obfuscator.0.decrypt_block(&incoming_packet[16..32], &mut buffer[16..32]);
|
incoming_obfuscator.0.decrypt_block(&incoming_packet[16..32], &mut buffer[16..32]);
|
||||||
|
@ -531,10 +515,7 @@ impl<O> Session<O> {
|
||||||
// NIST/FIPS allows HKDF with HMAC(salt, key) and salt is allowed to be anything. This way if the PSK is not
|
// NIST/FIPS allows HKDF with HMAC(salt, key) and salt is allowed to be anything. This way if the PSK is not
|
||||||
// FIPS compliant the compliance of the entire key derivation is not invalidated. Both inputs are secrets of
|
// FIPS compliant the compliance of the entire key derivation is not invalidated. Both inputs are secrets of
|
||||||
// fixed size so this shouldn't matter cryptographically.
|
// fixed size so this shouldn't matter cryptographically.
|
||||||
let key = Secret(hmac_sha512(
|
let key = Secret(hmac_sha512(session.psk.as_bytes(), &hmac_sha512(&hmac_sha512(&hmac_sha512(key.as_bytes(), bob_e0_keypair.public_key_bytes()), e0e0.as_bytes()), se0.as_bytes())));
|
||||||
session.psk.as_bytes(),
|
|
||||||
&hmac_sha512(&hmac_sha512(&hmac_sha512(key.as_bytes(), bob_e0_keypair.public_key_bytes()), e0e0.as_bytes()), se0.as_bytes()),
|
|
||||||
));
|
|
||||||
|
|
||||||
// At this point we've completed Noise_IK key derivation with NIST P-384 ECDH, but see final step below...
|
// At this point we've completed Noise_IK key derivation with NIST P-384 ECDH, but see final step below...
|
||||||
|
|
||||||
|
@ -594,10 +575,7 @@ impl<O> Session<O> {
|
||||||
.ok_or(Error::FailedAuthentication)?;
|
.ok_or(Error::FailedAuthentication)?;
|
||||||
let se0 = local_s_keypair_p384.agree(&bob_e0_public).ok_or(Error::FailedAuthentication)?;
|
let se0 = local_s_keypair_p384.agree(&bob_e0_public).ok_or(Error::FailedAuthentication)?;
|
||||||
|
|
||||||
let key = Secret(hmac_sha512(
|
let key = Secret(hmac_sha512(session.psk.as_bytes(), &hmac_sha512(&hmac_sha512(&hmac_sha512(offer.key.as_bytes(), bob_e0_public.as_bytes()), e0e0.as_bytes()), se0.as_bytes())));
|
||||||
session.psk.as_bytes(),
|
|
||||||
&hmac_sha512(&hmac_sha512(&hmac_sha512(offer.key.as_bytes(), bob_e0_public.as_bytes()), e0e0.as_bytes()), se0.as_bytes()),
|
|
||||||
));
|
|
||||||
|
|
||||||
let original_ciphertext = buffer.clone();
|
let original_ciphertext = buffer.clone();
|
||||||
let mut c = AesGcm::new(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_AES_GCM_BOB_TO_ALICE).first_n::<32>(), false);
|
let mut c = AesGcm::new(kbkdf512(key.as_bytes(), KBKDF_KEY_USAGE_LABEL_AES_GCM_BOB_TO_ALICE).first_n::<32>(), false);
|
||||||
|
@ -965,14 +943,7 @@ fn parse_KEY_OFFER_after_header<const STATIC_PUBLIC_SIZE: usize>(mut b: &[u8]) -
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn assemble_KEY_COUNTER_OFFER<const MAX_PACKET_SIZE: usize>(
|
fn assemble_KEY_COUNTER_OFFER<const MAX_PACKET_SIZE: usize>(buffer: &mut [u8; MAX_PACKET_SIZE], counter: CounterValue, alice_session_id: SessionId, bob_e0_public: &P384PublicKey, bob_session_id: SessionId, bob_e1_public: Option<&[u8; pqc_kyber::KYBER_CIPHERTEXTBYTES]>) -> usize {
|
||||||
buffer: &mut [u8; MAX_PACKET_SIZE],
|
|
||||||
counter: CounterValue,
|
|
||||||
alice_session_id: SessionId,
|
|
||||||
bob_e0_public: &P384PublicKey,
|
|
||||||
bob_session_id: SessionId,
|
|
||||||
bob_e1_public: Option<&[u8; pqc_kyber::KYBER_CIPHERTEXTBYTES]>,
|
|
||||||
) -> usize {
|
|
||||||
buffer[0] = PACKET_TYPE_KEY_COUNTER_OFFER;
|
buffer[0] = PACKET_TYPE_KEY_COUNTER_OFFER;
|
||||||
alice_session_id.copy_to(&mut buffer[1..7]);
|
alice_session_id.copy_to(&mut buffer[1..7]);
|
||||||
buffer[7..11].copy_from_slice(&counter.to_bytes());
|
buffer[7..11].copy_from_slice(&counter.to_bytes());
|
||||||
|
|
|
@ -1,208 +1,307 @@
|
||||||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||||
|
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::os::raw::{c_int, c_ulong, c_void};
|
|
||||||
use std::ptr::{null, write_volatile};
|
|
||||||
|
|
||||||
use foreign_types::{ForeignType, ForeignTypeRef};
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use openssl::bn::{BigNum, BigNumContext};
|
|
||||||
use openssl::ec::{EcKey, EcPoint, EcPointRef, PointConversionForm};
|
|
||||||
use openssl::ecdsa::EcdsaSig;
|
|
||||||
use openssl::nid::Nid;
|
|
||||||
use openssl::pkey::{Private, Public};
|
|
||||||
|
|
||||||
use crate::hash::SHA384;
|
|
||||||
use crate::secret::Secret;
|
|
||||||
|
|
||||||
pub const P384_PUBLIC_KEY_SIZE: usize = 49;
|
pub const P384_PUBLIC_KEY_SIZE: usize = 49;
|
||||||
pub const P384_SECRET_KEY_SIZE: usize = 48;
|
pub const P384_SECRET_KEY_SIZE: usize = 48;
|
||||||
pub const P384_ECDSA_SIGNATURE_SIZE: usize = 96;
|
pub const P384_ECDSA_SIGNATURE_SIZE: usize = 96;
|
||||||
pub const P384_ECDH_SHARED_SECRET_SIZE: usize = 48;
|
pub const P384_ECDH_SHARED_SECRET_SIZE: usize = 48;
|
||||||
|
|
||||||
//#[link(name="crypto")]
|
/// Version using the slightly faster code in p384_internal.rs
|
||||||
extern "C" {
|
mod internal {
|
||||||
fn ECDH_compute_key(out: *mut c_void, outlen: c_ulong, pub_key: *mut c_void, ecdh: *mut c_void, kdf: *const c_void) -> c_int;
|
use crate::p384_internal::{ecc_make_key, ecdh_shared_secret, ecdsa_sign, ecdsa_verify};
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
use crate::hash::SHA384;
|
||||||
static ref GROUP_P384: openssl::ec::EcGroup = openssl::ec::EcGroup::from_curve_name(Nid::SECP384R1).unwrap();
|
use crate::secret::Secret;
|
||||||
}
|
|
||||||
|
|
||||||
/// A NIST P-384 ECDH/ECDSA public key.
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
#[derive(Clone)]
|
pub struct P384PublicKey([u8; 49]);
|
||||||
pub struct P384PublicKey {
|
|
||||||
key: EcKey<Public>,
|
|
||||||
bytes: [u8; 49],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl P384PublicKey {
|
impl P384PublicKey {
|
||||||
fn new_from_point(key: &EcPointRef) -> Self {
|
#[inline(always)]
|
||||||
let mut bnc = BigNumContext::new().unwrap();
|
pub fn from_bytes(b: &[u8]) -> Option<P384PublicKey> {
|
||||||
let kb = key.to_bytes(GROUP_P384.as_ref(), PointConversionForm::COMPRESSED, &mut bnc).unwrap();
|
if b.len() == 49 {
|
||||||
let mut bytes = [0_u8; 49];
|
Some(Self(b.try_into().unwrap()))
|
||||||
bytes[(49 - kb.len())..].copy_from_slice(kb.as_slice());
|
|
||||||
Self {
|
|
||||||
key: EcKey::from_public_key(GROUP_P384.as_ref(), key).unwrap(),
|
|
||||||
bytes,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_bytes(b: &[u8]) -> Option<P384PublicKey> {
|
|
||||||
if b.len() == 49 {
|
|
||||||
let mut bnc = BigNumContext::new().unwrap();
|
|
||||||
let key = EcPoint::from_bytes(GROUP_P384.as_ref(), b, &mut bnc);
|
|
||||||
if key.is_ok() {
|
|
||||||
let key = key.unwrap();
|
|
||||||
if key.is_on_curve(GROUP_P384.as_ref(), &mut bnc).unwrap_or(false) {
|
|
||||||
let key = EcKey::from_public_key(GROUP_P384.as_ref(), key.as_ref());
|
|
||||||
if key.is_ok() {
|
|
||||||
return Some(Self { key: key.unwrap(), bytes: b.try_into().unwrap() });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn verify(&self, msg: &[u8], signature: &[u8]) -> bool {
|
|
||||||
if signature.len() == 96 {
|
|
||||||
let r = BigNum::from_slice(&signature[0..48]);
|
|
||||||
let s = BigNum::from_slice(&signature[48..96]);
|
|
||||||
if r.is_ok() && s.is_ok() {
|
|
||||||
let r = r.unwrap();
|
|
||||||
let s = s.unwrap();
|
|
||||||
let z = BigNum::from_u32(0).unwrap();
|
|
||||||
// Check that r and s are >=1 just in case the OpenSSL version or an OpenSSL API lookalike is
|
|
||||||
// vulnerable to this, since a bunch of vulnerabilities involving zero r/s just made the rounds.
|
|
||||||
if r.gt(&z) && s.gt(&z) {
|
|
||||||
let sig = EcdsaSig::from_private_components(r, s);
|
|
||||||
if sig.is_ok() {
|
|
||||||
return sig.unwrap().verify(&SHA384::hash(msg), self.key.as_ref()).unwrap_or(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn as_bytes(&self) -> &[u8; 49] {
|
|
||||||
&self.bytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for P384PublicKey {
|
|
||||||
#[inline(always)]
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.bytes == other.bytes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for P384PublicKey {}
|
|
||||||
|
|
||||||
unsafe impl Sync for P384PublicKey {}
|
|
||||||
|
|
||||||
/// A NIST P-384 ECDH/ECDSA public/private key pair.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct P384KeyPair {
|
|
||||||
pair: EcKey<Private>,
|
|
||||||
public: P384PublicKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl P384KeyPair {
|
|
||||||
pub fn generate() -> P384KeyPair {
|
|
||||||
let pair = EcKey::generate(GROUP_P384.as_ref()).unwrap(); // failure implies a serious problem
|
|
||||||
assert!(pair.check_key().is_ok()); // also would imply a serious problem
|
|
||||||
let public = P384PublicKey::new_from_point(pair.public_key());
|
|
||||||
Self { pair, public }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_bytes(public_bytes: &[u8], secret_bytes: &[u8]) -> Option<P384KeyPair> {
|
|
||||||
if public_bytes.len() == 49 && secret_bytes.len() == 48 {
|
|
||||||
P384PublicKey::from_bytes(public_bytes).map_or(None, |public| {
|
|
||||||
BigNum::from_slice(secret_bytes).map_or(None, |private| {
|
|
||||||
let pair = EcKey::from_private_components(GROUP_P384.as_ref(), private.as_ref(), public.key.public_key());
|
|
||||||
if pair.is_ok() {
|
|
||||||
let pair = pair.unwrap();
|
|
||||||
if pair.check_key().is_ok() {
|
|
||||||
Some(Self { pair, public })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn public_key(&self) -> &P384PublicKey {
|
|
||||||
&self.public
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn public_key_bytes(&self) -> &[u8; P384_PUBLIC_KEY_SIZE] {
|
|
||||||
&self.public.bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn secret_key_bytes(&self) -> Secret<P384_SECRET_KEY_SIZE> {
|
|
||||||
let mut tmp: Secret<P384_SECRET_KEY_SIZE> = Secret::default();
|
|
||||||
let mut k = self.pair.private_key().to_vec();
|
|
||||||
tmp.0[(48 - k.len())..].copy_from_slice(k.as_slice());
|
|
||||||
unsafe {
|
|
||||||
// Force zero memory occupied by temporary vector before releasing.
|
|
||||||
let kp = k.as_mut_ptr();
|
|
||||||
for i in 0..k.len() {
|
|
||||||
write_volatile(kp.add(i), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sign a message with ECDSA/SHA384.
|
|
||||||
pub fn sign(&self, msg: &[u8]) -> [u8; P384_ECDSA_SIGNATURE_SIZE] {
|
|
||||||
let sig = EcdsaSig::sign(&SHA384::hash(msg), self.pair.as_ref()).unwrap();
|
|
||||||
let r = sig.r().to_vec();
|
|
||||||
let s = sig.s().to_vec();
|
|
||||||
assert!(!r.is_empty() && !s.is_empty() && r.len() <= 48 && s.len() <= 48);
|
|
||||||
let mut b = [0_u8; P384_ECDSA_SIGNATURE_SIZE];
|
|
||||||
b[(48 - r.len())..48].copy_from_slice(r.as_slice());
|
|
||||||
b[(96 - s.len())..96].copy_from_slice(s.as_slice());
|
|
||||||
b
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Perform ECDH key agreement, returning the raw (un-hashed!) ECDH secret.
|
|
||||||
///
|
|
||||||
/// This secret should not be used directly. It should be hashed and perhaps used in a KDF.
|
|
||||||
pub fn agree(&self, other_public: &P384PublicKey) -> Option<Secret<P384_ECDH_SHARED_SECRET_SIZE>> {
|
|
||||||
unsafe {
|
|
||||||
let mut s: Secret<P384_ECDH_SHARED_SECRET_SIZE> = Secret::default();
|
|
||||||
if ECDH_compute_key(s.0.as_mut_ptr().cast(), 48, other_public.key.public_key().as_ptr().cast(), self.pair.as_ptr().cast(), null()) == 48 {
|
|
||||||
Some(s)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn verify(&self, msg: &[u8], signature: &[u8]) -> bool {
|
||||||
|
if signature.len() == 96 {
|
||||||
|
unsafe {
|
||||||
|
return ecdsa_verify(self.0.as_ptr().cast(), SHA384::hash(msg).as_ptr().cast(), signature.as_ptr().cast()) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn as_bytes(&self) -> &[u8; 49] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
pub struct P384KeyPair(P384PublicKey, Secret<48>);
|
||||||
|
|
||||||
|
impl P384KeyPair {
|
||||||
|
pub fn generate() -> P384KeyPair {
|
||||||
|
let mut kp = Self(P384PublicKey([0_u8; 49]), Secret::new());
|
||||||
|
unsafe { ecc_make_key(kp.0 .0.as_mut_ptr().cast(), kp.1 .0.as_mut_ptr().cast()) };
|
||||||
|
kp
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_bytes(public_bytes: &[u8], secret_bytes: &[u8]) -> Option<P384KeyPair> {
|
||||||
|
if public_bytes.len() == 49 && secret_bytes.len() == 48 {
|
||||||
|
Some(Self(P384PublicKey(public_bytes.try_into().unwrap()), Secret(secret_bytes.try_into().unwrap())))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn public_key(&self) -> &P384PublicKey {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn public_key_bytes(&self) -> &[u8; 49] {
|
||||||
|
&self.0 .0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn secret_key_bytes(&self) -> Secret<48> {
|
||||||
|
self.1.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sign(&self, msg: &[u8]) -> [u8; 96] {
|
||||||
|
let msg = SHA384::hash(msg);
|
||||||
|
let mut sig = [0_u8; 96];
|
||||||
|
unsafe {
|
||||||
|
ecdsa_sign(self.1 .0.as_ptr().cast(), msg.as_ptr().cast(), sig.as_mut_ptr().cast());
|
||||||
|
}
|
||||||
|
sig
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn agree(&self, other_public: &P384PublicKey) -> Option<Secret<48>> {
|
||||||
|
let mut k = Secret::new();
|
||||||
|
unsafe {
|
||||||
|
ecdh_shared_secret(other_public.0.as_ptr().cast(), self.1 .0.as_ptr().cast(), k.0.as_mut_ptr().cast());
|
||||||
|
}
|
||||||
|
Some(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl P384KeyPair {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for P384KeyPair {
|
/*
|
||||||
#[inline(always)]
|
// Version using OpenSSL's ECC
|
||||||
fn eq(&self, other: &Self) -> bool {
|
mod openssl_based {
|
||||||
self.pair.private_key().eq(other.pair.private_key()) && self.public.bytes.eq(&other.public.bytes)
|
use std::convert::TryInto;
|
||||||
|
use std::os::raw::{c_int, c_ulong, c_void};
|
||||||
|
use std::ptr::{null, write_volatile};
|
||||||
|
|
||||||
|
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use openssl::bn::{BigNum, BigNumContext};
|
||||||
|
use openssl::ec::{EcKey, EcPoint, EcPointRef, PointConversionForm};
|
||||||
|
use openssl::ecdsa::EcdsaSig;
|
||||||
|
use openssl::nid::Nid;
|
||||||
|
use openssl::pkey::{Private, Public};
|
||||||
|
|
||||||
|
use crate::hash::SHA384;
|
||||||
|
use crate::secret::Secret;
|
||||||
|
|
||||||
|
use super::{P384_ECDH_SHARED_SECRET_SIZE, P384_ECDSA_SIGNATURE_SIZE, P384_PUBLIC_KEY_SIZE, P384_SECRET_KEY_SIZE};
|
||||||
|
|
||||||
|
//#[link(name="crypto")]
|
||||||
|
extern "C" {
|
||||||
|
fn ECDH_compute_key(out: *mut c_void, outlen: c_ulong, pub_key: *mut c_void, ecdh: *mut c_void, kdf: *const c_void) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref GROUP_P384: openssl::ec::EcGroup = openssl::ec::EcGroup::from_curve_name(Nid::SECP384R1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A NIST P-384 ECDH/ECDSA public key.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct P384PublicKey {
|
||||||
|
key: EcKey<Public>,
|
||||||
|
bytes: [u8; 49],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl P384PublicKey {
|
||||||
|
fn new_from_point(key: &EcPointRef) -> Self {
|
||||||
|
let mut bnc = BigNumContext::new().unwrap();
|
||||||
|
let kb = key.to_bytes(GROUP_P384.as_ref(), PointConversionForm::COMPRESSED, &mut bnc).unwrap();
|
||||||
|
let mut bytes = [0_u8; 49];
|
||||||
|
bytes[(49 - kb.len())..].copy_from_slice(kb.as_slice());
|
||||||
|
Self {
|
||||||
|
key: EcKey::from_public_key(GROUP_P384.as_ref(), key).unwrap(),
|
||||||
|
bytes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_bytes(b: &[u8]) -> Option<P384PublicKey> {
|
||||||
|
if b.len() == 49 {
|
||||||
|
let mut bnc = BigNumContext::new().unwrap();
|
||||||
|
let key = EcPoint::from_bytes(GROUP_P384.as_ref(), b, &mut bnc);
|
||||||
|
if key.is_ok() {
|
||||||
|
let key = key.unwrap();
|
||||||
|
if key.is_on_curve(GROUP_P384.as_ref(), &mut bnc).unwrap_or(false) {
|
||||||
|
let key = EcKey::from_public_key(GROUP_P384.as_ref(), key.as_ref());
|
||||||
|
if key.is_ok() {
|
||||||
|
return Some(Self { key: key.unwrap(), bytes: b.try_into().unwrap() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(&self, msg: &[u8], signature: &[u8]) -> bool {
|
||||||
|
if signature.len() == 96 {
|
||||||
|
let r = BigNum::from_slice(&signature[0..48]);
|
||||||
|
let s = BigNum::from_slice(&signature[48..96]);
|
||||||
|
if r.is_ok() && s.is_ok() {
|
||||||
|
let r = r.unwrap();
|
||||||
|
let s = s.unwrap();
|
||||||
|
let z = BigNum::from_u32(0).unwrap();
|
||||||
|
// Check that r and s are >=1 just in case the OpenSSL version or an OpenSSL API lookalike is
|
||||||
|
// vulnerable to this, since a bunch of vulnerabilities involving zero r/s just made the rounds.
|
||||||
|
if r.gt(&z) && s.gt(&z) {
|
||||||
|
let sig = EcdsaSig::from_private_components(r, s);
|
||||||
|
if sig.is_ok() {
|
||||||
|
return sig.unwrap().verify(&SHA384::hash(msg), self.key.as_ref()).unwrap_or(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn as_bytes(&self) -> &[u8; 49] {
|
||||||
|
&self.bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for P384PublicKey {
|
||||||
|
#[inline(always)]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.bytes == other.bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for P384PublicKey {}
|
||||||
|
|
||||||
|
unsafe impl Sync for P384PublicKey {}
|
||||||
|
|
||||||
|
/// A NIST P-384 ECDH/ECDSA public/private key pair.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct P384KeyPair {
|
||||||
|
pair: EcKey<Private>,
|
||||||
|
public: P384PublicKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl P384KeyPair {
|
||||||
|
pub fn generate() -> P384KeyPair {
|
||||||
|
let pair = EcKey::generate(GROUP_P384.as_ref()).unwrap(); // failure implies a serious problem
|
||||||
|
assert!(pair.check_key().is_ok()); // also would imply a serious problem
|
||||||
|
let public = P384PublicKey::new_from_point(pair.public_key());
|
||||||
|
Self { pair, public }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_bytes(public_bytes: &[u8], secret_bytes: &[u8]) -> Option<P384KeyPair> {
|
||||||
|
if public_bytes.len() == 49 && secret_bytes.len() == 48 {
|
||||||
|
P384PublicKey::from_bytes(public_bytes).map_or(None, |public| {
|
||||||
|
BigNum::from_slice(secret_bytes).map_or(None, |private| {
|
||||||
|
let pair = EcKey::from_private_components(GROUP_P384.as_ref(), private.as_ref(), public.key.public_key());
|
||||||
|
if pair.is_ok() {
|
||||||
|
let pair = pair.unwrap();
|
||||||
|
if pair.check_key().is_ok() {
|
||||||
|
Some(Self { pair, public })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn public_key(&self) -> &P384PublicKey {
|
||||||
|
&self.public
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn public_key_bytes(&self) -> &[u8; P384_PUBLIC_KEY_SIZE] {
|
||||||
|
&self.public.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn secret_key_bytes(&self) -> Secret<P384_SECRET_KEY_SIZE> {
|
||||||
|
let mut tmp: Secret<P384_SECRET_KEY_SIZE> = Secret::default();
|
||||||
|
let mut k = self.pair.private_key().to_vec();
|
||||||
|
tmp.0[(48 - k.len())..].copy_from_slice(k.as_slice());
|
||||||
|
unsafe {
|
||||||
|
// Force zero memory occupied by temporary vector before releasing.
|
||||||
|
let kp = k.as_mut_ptr();
|
||||||
|
for i in 0..k.len() {
|
||||||
|
write_volatile(kp.add(i), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sign a message with ECDSA/SHA384.
|
||||||
|
pub fn sign(&self, msg: &[u8]) -> [u8; P384_ECDSA_SIGNATURE_SIZE] {
|
||||||
|
let sig = EcdsaSig::sign(&SHA384::hash(msg), self.pair.as_ref()).unwrap();
|
||||||
|
let r = sig.r().to_vec();
|
||||||
|
let s = sig.s().to_vec();
|
||||||
|
assert!(!r.is_empty() && !s.is_empty() && r.len() <= 48 && s.len() <= 48);
|
||||||
|
let mut b = [0_u8; P384_ECDSA_SIGNATURE_SIZE];
|
||||||
|
b[(48 - r.len())..48].copy_from_slice(r.as_slice());
|
||||||
|
b[(96 - s.len())..96].copy_from_slice(s.as_slice());
|
||||||
|
b
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform ECDH key agreement, returning the raw (un-hashed!) ECDH secret.
|
||||||
|
///
|
||||||
|
/// This secret should not be used directly. It should be hashed and perhaps used in a KDF.
|
||||||
|
pub fn agree(&self, other_public: &P384PublicKey) -> Option<Secret<P384_ECDH_SHARED_SECRET_SIZE>> {
|
||||||
|
unsafe {
|
||||||
|
let mut s: Secret<P384_ECDH_SHARED_SECRET_SIZE> = Secret::default();
|
||||||
|
if ECDH_compute_key(s.0.as_mut_ptr().cast(), 48, other_public.key.public_key().as_ptr().cast(), self.pair.as_ptr().cast(), null()) == 48 {
|
||||||
|
Some(s)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for P384KeyPair {
|
||||||
|
#[inline(always)]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.pair.private_key().eq(other.pair.private_key()) && self.public.bytes.eq(&other.public.bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for P384KeyPair {}
|
||||||
|
|
||||||
|
unsafe impl Send for P384KeyPair {}
|
||||||
|
|
||||||
|
unsafe impl Sync for P384KeyPair {}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
impl Eq for P384KeyPair {}
|
pub use internal::*;
|
||||||
|
//pub use openssl_based::*;
|
||||||
unsafe impl Send for P384KeyPair {}
|
|
||||||
|
|
||||||
unsafe impl Sync for P384KeyPair {}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
909
core-crypto/src/p384_internal.rs
Normal file
909
core-crypto/src/p384_internal.rs
Normal file
|
@ -0,0 +1,909 @@
|
||||||
|
// This is EASY-ECC by Kenneth MacKay
|
||||||
|
// https://github.com/esxgx/easy-ecc
|
||||||
|
//
|
||||||
|
// It inherits the BSD 2-Clause license, not ZeroTier's license.
|
||||||
|
//
|
||||||
|
// Translated to Rust using: https://c2rust.com
|
||||||
|
|
||||||
|
#![allow(dead_code, mutable_transmutes, non_camel_case_types, non_snake_case, non_upper_case_globals, unused_assignments, unused_mut)]
|
||||||
|
|
||||||
|
pub mod libc {
|
||||||
|
pub type c_uchar = u8;
|
||||||
|
pub type c_ulong = u64;
|
||||||
|
pub type c_long = i64;
|
||||||
|
pub type c_uint = u32;
|
||||||
|
pub type c_int = i32;
|
||||||
|
pub type c_ulonglong = u64;
|
||||||
|
pub type c_longlong = i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type uint8_t = libc::c_uchar;
|
||||||
|
pub type uint64_t = libc::c_ulong;
|
||||||
|
pub type uint = libc::c_uint;
|
||||||
|
pub type uint128_t = u128;
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct EccPoint {
|
||||||
|
pub x: [u64; 6],
|
||||||
|
pub y: [u64; 6],
|
||||||
|
}
|
||||||
|
static mut curve_p: [uint64_t; 6] = [
|
||||||
|
0xffffffff as libc::c_uint as uint64_t,
|
||||||
|
0xffffffff00000000 as libc::c_ulong,
|
||||||
|
0xfffffffffffffffe as libc::c_ulong,
|
||||||
|
0xffffffffffffffff as libc::c_ulong,
|
||||||
|
0xffffffffffffffff as libc::c_ulong,
|
||||||
|
0xffffffffffffffff as libc::c_ulong,
|
||||||
|
];
|
||||||
|
static mut curve_b: [uint64_t; 6] = [
|
||||||
|
0x2a85c8edd3ec2aef as libc::c_long as uint64_t,
|
||||||
|
0xc656398d8a2ed19d as libc::c_ulong,
|
||||||
|
0x314088f5013875a as libc::c_long as uint64_t,
|
||||||
|
0x181d9c6efe814112 as libc::c_long as uint64_t,
|
||||||
|
0x988e056be3f82d19 as libc::c_ulong,
|
||||||
|
0xb3312fa7e23ee7e4 as libc::c_ulong,
|
||||||
|
];
|
||||||
|
static mut curve_G: EccPoint = {
|
||||||
|
let mut init = EccPoint {
|
||||||
|
x: [
|
||||||
|
0x3a545e3872760ab7 as libc::c_long as uint64_t,
|
||||||
|
0x5502f25dbf55296c as libc::c_long as uint64_t,
|
||||||
|
0x59f741e082542a38 as libc::c_long as uint64_t,
|
||||||
|
0x6e1d3b628ba79b98 as libc::c_long as uint64_t,
|
||||||
|
0x8eb1c71ef320ad74 as libc::c_ulong,
|
||||||
|
0xaa87ca22be8b0537 as libc::c_ulong,
|
||||||
|
],
|
||||||
|
y: [
|
||||||
|
0x7a431d7c90ea0e5f as libc::c_long as uint64_t,
|
||||||
|
0xa60b1ce1d7e819d as libc::c_long as uint64_t,
|
||||||
|
0xe9da3113b5f0b8c0 as libc::c_ulong,
|
||||||
|
0xf8f41dbd289a147c as libc::c_ulong,
|
||||||
|
0x5d9e98bf9292dc29 as libc::c_long as uint64_t,
|
||||||
|
0x3617de4a96262c6f as libc::c_long as uint64_t,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
init
|
||||||
|
};
|
||||||
|
static mut curve_n: [uint64_t; 6] = [
|
||||||
|
0xecec196accc52973 as libc::c_ulong,
|
||||||
|
0x581a0db248b0a77a as libc::c_long as uint64_t,
|
||||||
|
0xc7634d81f4372ddf as libc::c_ulong,
|
||||||
|
0xffffffffffffffff as libc::c_ulong,
|
||||||
|
0xffffffffffffffff as libc::c_ulong,
|
||||||
|
0xffffffffffffffff as libc::c_ulong,
|
||||||
|
];
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn getRandomNumber(mut p_vli: *mut uint64_t) -> libc::c_int {
|
||||||
|
crate::random::fill_bytes_secure(&mut *std::ptr::slice_from_raw_parts_mut(p_vli.cast(), 48));
|
||||||
|
return 1 as libc::c_int;
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_clear(mut p_vli: *mut uint64_t) {
|
||||||
|
let mut i: uint = 0;
|
||||||
|
i = 0 as libc::c_int as uint;
|
||||||
|
while i < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
*p_vli.offset(i as isize) = 0 as libc::c_int as uint64_t;
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Returns 1 if p_vli == 0, 0 otherwise. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_isZero(mut p_vli: *mut uint64_t) -> libc::c_int {
|
||||||
|
let mut i: uint = 0;
|
||||||
|
i = 0 as libc::c_int as uint;
|
||||||
|
while i < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
if *p_vli.offset(i as isize) != 0 {
|
||||||
|
return 0 as libc::c_int;
|
||||||
|
}
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
return 1 as libc::c_int;
|
||||||
|
}
|
||||||
|
/* Returns nonzero if bit p_bit of p_vli is set. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_testBit(mut p_vli: *mut uint64_t, mut p_bit: uint) -> uint64_t {
|
||||||
|
return *p_vli.offset(p_bit.wrapping_div(64 as libc::c_int as libc::c_uint) as isize) & (1 as libc::c_int as uint64_t) << p_bit.wrapping_rem(64 as libc::c_int as libc::c_uint);
|
||||||
|
}
|
||||||
|
/* Counts the number of 64-bit "digits" in p_vli. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_numDigits(mut p_vli: *mut uint64_t) -> uint {
|
||||||
|
let mut i: libc::c_int = 0;
|
||||||
|
/* Search from the end until we find a non-zero digit.
|
||||||
|
We do it in reverse because we expect that most digits will be nonzero. */
|
||||||
|
i = 48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int;
|
||||||
|
while i >= 0 as libc::c_int && *p_vli.offset(i as isize) == 0 as libc::c_int as libc::c_ulong {
|
||||||
|
i -= 1
|
||||||
|
}
|
||||||
|
return (i + 1 as libc::c_int) as uint;
|
||||||
|
}
|
||||||
|
/* Counts the number of bits required for p_vli. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_numBits(mut p_vli: *mut uint64_t) -> uint {
|
||||||
|
let mut i: uint = 0;
|
||||||
|
let mut l_digit: uint64_t = 0;
|
||||||
|
let mut l_numDigits: uint = vli_numDigits(p_vli);
|
||||||
|
if l_numDigits == 0 as libc::c_int as libc::c_uint {
|
||||||
|
return 0 as libc::c_int as uint;
|
||||||
|
}
|
||||||
|
l_digit = *p_vli.offset(l_numDigits.wrapping_sub(1 as libc::c_int as libc::c_uint) as isize);
|
||||||
|
i = 0 as libc::c_int as uint;
|
||||||
|
while l_digit != 0 {
|
||||||
|
l_digit >>= 1 as libc::c_int;
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
return l_numDigits.wrapping_sub(1 as libc::c_int as libc::c_uint).wrapping_mul(64 as libc::c_int as libc::c_uint).wrapping_add(i);
|
||||||
|
}
|
||||||
|
/* Sets p_dest = p_src. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_set(mut p_dest: *mut uint64_t, mut p_src: *mut uint64_t) {
|
||||||
|
let mut i: uint = 0;
|
||||||
|
i = 0 as libc::c_int as uint;
|
||||||
|
while i < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
*p_dest.offset(i as isize) = *p_src.offset(i as isize);
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Returns sign of p_left - p_right. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_cmp(mut p_left: *mut uint64_t, mut p_right: *mut uint64_t) -> libc::c_int {
|
||||||
|
let mut i: libc::c_int = 0;
|
||||||
|
i = 48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int;
|
||||||
|
while i >= 0 as libc::c_int {
|
||||||
|
if *p_left.offset(i as isize) > *p_right.offset(i as isize) {
|
||||||
|
return 1 as libc::c_int;
|
||||||
|
} else {
|
||||||
|
if *p_left.offset(i as isize) < *p_right.offset(i as isize) {
|
||||||
|
return -(1 as libc::c_int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i -= 1
|
||||||
|
}
|
||||||
|
return 0 as libc::c_int;
|
||||||
|
}
|
||||||
|
/* Computes p_result = p_in << c, returning carry. Can modify in place (if p_result == p_in). 0 < p_shift < 64. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_lshift(mut p_result: *mut uint64_t, mut p_in: *mut uint64_t, mut p_shift: uint) -> uint64_t {
|
||||||
|
let mut l_carry: uint64_t = 0 as libc::c_int as uint64_t;
|
||||||
|
let mut i: uint = 0;
|
||||||
|
i = 0 as libc::c_int as uint;
|
||||||
|
while i < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
let mut l_temp: uint64_t = *p_in.offset(i as isize);
|
||||||
|
*p_result.offset(i as isize) = l_temp << p_shift | l_carry;
|
||||||
|
l_carry = l_temp >> (64 as libc::c_int as libc::c_uint).wrapping_sub(p_shift);
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
return l_carry;
|
||||||
|
}
|
||||||
|
/* Computes p_vli = p_vli >> 1. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_rshift1(mut p_vli: *mut uint64_t) {
|
||||||
|
let mut l_end: *mut uint64_t = p_vli;
|
||||||
|
let mut l_carry: uint64_t = 0 as libc::c_int as uint64_t;
|
||||||
|
p_vli = p_vli.offset((48 as libc::c_int / 8 as libc::c_int) as isize);
|
||||||
|
loop {
|
||||||
|
let fresh0 = p_vli;
|
||||||
|
p_vli = p_vli.offset(-1);
|
||||||
|
if !(fresh0 > l_end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let mut l_temp: uint64_t = *p_vli;
|
||||||
|
*p_vli = l_temp >> 1 as libc::c_int | l_carry;
|
||||||
|
l_carry = l_temp << 63 as libc::c_int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Computes p_result = p_left + p_right, returning carry. Can modify in place. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_add(mut p_result: *mut uint64_t, mut p_left: *mut uint64_t, mut p_right: *mut uint64_t) -> uint64_t {
|
||||||
|
let mut l_carry: uint64_t = 0 as libc::c_int as uint64_t;
|
||||||
|
let mut i: uint = 0;
|
||||||
|
i = 0 as libc::c_int as uint;
|
||||||
|
while i < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
let mut l_sum: uint64_t = (*p_left.offset(i as isize)).wrapping_add(*p_right.offset(i as isize)).wrapping_add(l_carry);
|
||||||
|
if l_sum != *p_left.offset(i as isize) {
|
||||||
|
l_carry = (l_sum < *p_left.offset(i as isize)) as libc::c_int as uint64_t
|
||||||
|
}
|
||||||
|
*p_result.offset(i as isize) = l_sum;
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
return l_carry;
|
||||||
|
}
|
||||||
|
/* Computes p_result = p_left - p_right, returning borrow. Can modify in place. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_sub(mut p_result: *mut uint64_t, mut p_left: *mut uint64_t, mut p_right: *mut uint64_t) -> uint64_t {
|
||||||
|
let mut l_borrow: uint64_t = 0 as libc::c_int as uint64_t;
|
||||||
|
let mut i: uint = 0;
|
||||||
|
i = 0 as libc::c_int as uint;
|
||||||
|
while i < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
let mut l_diff: uint64_t = (*p_left.offset(i as isize)).wrapping_sub(*p_right.offset(i as isize)).wrapping_sub(l_borrow);
|
||||||
|
if l_diff != *p_left.offset(i as isize) {
|
||||||
|
l_borrow = (l_diff > *p_left.offset(i as isize)) as libc::c_int as uint64_t
|
||||||
|
}
|
||||||
|
*p_result.offset(i as isize) = l_diff;
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
return l_borrow;
|
||||||
|
}
|
||||||
|
/* Computes p_result = p_left * p_right. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_mult(mut p_result: *mut uint64_t, mut p_left: *mut uint64_t, mut p_right: *mut uint64_t) {
|
||||||
|
let mut r01: uint128_t = 0 as libc::c_int as uint128_t;
|
||||||
|
let mut r2: uint64_t = 0 as libc::c_int as uint64_t;
|
||||||
|
let mut i: uint = 0;
|
||||||
|
let mut k: uint = 0;
|
||||||
|
/* Compute each digit of p_result in sequence, maintaining the carries. */
|
||||||
|
k = 0 as libc::c_int as uint;
|
||||||
|
while k < (48 as libc::c_int / 8 as libc::c_int * 2 as libc::c_int - 1 as libc::c_int) as libc::c_uint {
|
||||||
|
let mut l_min: uint = if k < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
0 as libc::c_int as libc::c_uint
|
||||||
|
} else {
|
||||||
|
k.wrapping_add(1 as libc::c_int as libc::c_uint).wrapping_sub((48 as libc::c_int / 8 as libc::c_int) as libc::c_uint)
|
||||||
|
};
|
||||||
|
i = l_min;
|
||||||
|
while i <= k && i < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
let mut l_product: uint128_t = (*p_left.offset(i as isize) as uint128_t).wrapping_mul(*p_right.offset(k.wrapping_sub(i) as isize) as u128);
|
||||||
|
r01 = (r01 as u128).wrapping_add(l_product) as uint128_t as uint128_t;
|
||||||
|
r2 = (r2 as libc::c_ulong).wrapping_add((r01 < l_product) as libc::c_int as libc::c_ulong) as uint64_t as uint64_t;
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
*p_result.offset(k as isize) = r01 as uint64_t;
|
||||||
|
r01 = r01 >> 64 as libc::c_int | (r2 as uint128_t) << 64 as libc::c_int;
|
||||||
|
r2 = 0 as libc::c_int as uint64_t;
|
||||||
|
k = k.wrapping_add(1)
|
||||||
|
}
|
||||||
|
*p_result.offset((48 as libc::c_int / 8 as libc::c_int * 2 as libc::c_int - 1 as libc::c_int) as isize) = r01 as uint64_t;
|
||||||
|
}
|
||||||
|
/* Computes p_result = p_left^2. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_square(mut p_result: *mut uint64_t, mut p_left: *mut uint64_t) {
|
||||||
|
let mut r01: uint128_t = 0 as libc::c_int as uint128_t;
|
||||||
|
let mut r2: uint64_t = 0 as libc::c_int as uint64_t;
|
||||||
|
let mut i: uint = 0;
|
||||||
|
let mut k: uint = 0;
|
||||||
|
k = 0 as libc::c_int as uint;
|
||||||
|
while k < (48 as libc::c_int / 8 as libc::c_int * 2 as libc::c_int - 1 as libc::c_int) as libc::c_uint {
|
||||||
|
let mut l_min: uint = if k < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
0 as libc::c_int as libc::c_uint
|
||||||
|
} else {
|
||||||
|
k.wrapping_add(1 as libc::c_int as libc::c_uint).wrapping_sub((48 as libc::c_int / 8 as libc::c_int) as libc::c_uint)
|
||||||
|
};
|
||||||
|
i = l_min;
|
||||||
|
while i <= k && i <= k.wrapping_sub(i) {
|
||||||
|
let mut l_product: uint128_t = (*p_left.offset(i as isize) as uint128_t).wrapping_mul(*p_left.offset(k.wrapping_sub(i) as isize) as u128);
|
||||||
|
if i < k.wrapping_sub(i) {
|
||||||
|
r2 = (r2 as u128).wrapping_add(l_product >> 127 as libc::c_int) as uint64_t as uint64_t;
|
||||||
|
l_product = (l_product as u128).wrapping_mul(2 as libc::c_int as u128) as uint128_t as uint128_t
|
||||||
|
}
|
||||||
|
r01 = (r01 as u128).wrapping_add(l_product) as uint128_t as uint128_t;
|
||||||
|
r2 = (r2 as libc::c_ulong).wrapping_add((r01 < l_product) as libc::c_int as libc::c_ulong) as uint64_t as uint64_t;
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
*p_result.offset(k as isize) = r01 as uint64_t;
|
||||||
|
r01 = r01 >> 64 as libc::c_int | (r2 as uint128_t) << 64 as libc::c_int;
|
||||||
|
r2 = 0 as libc::c_int as uint64_t;
|
||||||
|
k = k.wrapping_add(1)
|
||||||
|
}
|
||||||
|
*p_result.offset((48 as libc::c_int / 8 as libc::c_int * 2 as libc::c_int - 1 as libc::c_int) as isize) = r01 as uint64_t;
|
||||||
|
}
|
||||||
|
/* #if SUPPORTS_INT128 */
|
||||||
|
/* SUPPORTS_INT128 */
|
||||||
|
/* Computes p_result = (p_left + p_right) % p_mod.
|
||||||
|
Assumes that p_left < p_mod and p_right < p_mod, p_result != p_mod. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_modAdd(mut p_result: *mut uint64_t, mut p_left: *mut uint64_t, mut p_right: *mut uint64_t, mut p_mod: *mut uint64_t) {
|
||||||
|
let mut l_carry: uint64_t = vli_add(p_result, p_left, p_right);
|
||||||
|
if l_carry != 0 || vli_cmp(p_result, p_mod) >= 0 as libc::c_int {
|
||||||
|
/* p_result > p_mod (p_result = p_mod + remainder), so subtract p_mod to get remainder. */
|
||||||
|
vli_sub(p_result, p_result, p_mod);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/* Computes p_result = (p_left - p_right) % p_mod.
|
||||||
|
Assumes that p_left < p_mod and p_right < p_mod, p_result != p_mod. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_modSub(mut p_result: *mut uint64_t, mut p_left: *mut uint64_t, mut p_right: *mut uint64_t, mut p_mod: *mut uint64_t) {
|
||||||
|
let mut l_borrow: uint64_t = vli_sub(p_result, p_left, p_right);
|
||||||
|
if l_borrow != 0 {
|
||||||
|
/* In this case, p_result == -diff == (max int) - diff.
|
||||||
|
Since -x % d == d - x, we can get the correct result from p_result + p_mod (with overflow). */
|
||||||
|
vli_add(p_result, p_result, p_mod);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//#elif ECC_CURVE == secp384r1
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn omega_mult(mut p_result: *mut uint64_t, mut p_right: *mut uint64_t) {
|
||||||
|
let mut l_tmp: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut l_carry: uint64_t = 0;
|
||||||
|
let mut l_diff: uint64_t = 0;
|
||||||
|
/* Multiply by (2^128 + 2^96 - 2^32 + 1). */
|
||||||
|
vli_set(p_result, p_right); /* 1 */
|
||||||
|
l_carry = vli_lshift(l_tmp.as_mut_ptr(), p_right, 32 as libc::c_int as uint); /* 2^96 + 1 */
|
||||||
|
*p_result.offset((1 as libc::c_int + 48 as libc::c_int / 8 as libc::c_int) as isize) = l_carry.wrapping_add(vli_add(p_result.offset(1 as libc::c_int as isize), p_result.offset(1 as libc::c_int as isize), l_tmp.as_mut_ptr())); /* 2^128 + 2^96 + 1 */
|
||||||
|
*p_result.offset((2 as libc::c_int + 48 as libc::c_int / 8 as libc::c_int) as isize) = vli_add(p_result.offset(2 as libc::c_int as isize), p_result.offset(2 as libc::c_int as isize), p_right); /* 2^128 + 2^96 - 2^32 + 1 */
|
||||||
|
l_carry = (l_carry as libc::c_ulong).wrapping_add(vli_sub(p_result, p_result, l_tmp.as_mut_ptr())) as uint64_t as uint64_t;
|
||||||
|
l_diff = (*p_result.offset((48 as libc::c_int / 8 as libc::c_int) as isize)).wrapping_sub(l_carry);
|
||||||
|
if l_diff > *p_result.offset((48 as libc::c_int / 8 as libc::c_int) as isize) {
|
||||||
|
/* Propagate borrow if necessary. */
|
||||||
|
let mut i: uint = 0;
|
||||||
|
i = (1 as libc::c_int + 48 as libc::c_int / 8 as libc::c_int) as uint;
|
||||||
|
loop {
|
||||||
|
let ref mut fresh1 = *p_result.offset(i as isize);
|
||||||
|
*fresh1 = (*fresh1).wrapping_sub(1);
|
||||||
|
if *p_result.offset(i as isize) != -(1 as libc::c_int) as uint64_t {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p_result.offset((48 as libc::c_int / 8 as libc::c_int) as isize) = l_diff;
|
||||||
|
}
|
||||||
|
/* Computes p_result = p_product % curve_p
|
||||||
|
see PDF "Comparing Elliptic Curve Cryptography and RSA on 8-bit CPUs"
|
||||||
|
section "Curve-Specific Optimizations" */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_mmod_fast(mut p_result: *mut uint64_t, mut p_product: *mut uint64_t) {
|
||||||
|
let mut l_tmp: [uint64_t; 12] = [0; 12];
|
||||||
|
while vli_isZero(p_product.offset((48 as libc::c_int / 8 as libc::c_int) as isize)) == 0 {
|
||||||
|
/* While c1 != 0 */
|
||||||
|
let mut l_carry: uint64_t = 0 as libc::c_int as uint64_t; /* tmp = w * c1 */
|
||||||
|
let mut i: uint = 0; /* p = c0 */
|
||||||
|
vli_clear(l_tmp.as_mut_ptr());
|
||||||
|
vli_clear(l_tmp.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize));
|
||||||
|
omega_mult(l_tmp.as_mut_ptr(), p_product.offset((48 as libc::c_int / 8 as libc::c_int) as isize));
|
||||||
|
vli_clear(p_product.offset((48 as libc::c_int / 8 as libc::c_int) as isize));
|
||||||
|
/* (c1, c0) = c0 + w * c1 */
|
||||||
|
i = 0 as libc::c_int as uint;
|
||||||
|
while i < (48 as libc::c_int / 8 as libc::c_int + 3 as libc::c_int) as libc::c_uint {
|
||||||
|
let mut l_sum: uint64_t = (*p_product.offset(i as isize)).wrapping_add(l_tmp[i as usize]).wrapping_add(l_carry);
|
||||||
|
if l_sum != *p_product.offset(i as isize) {
|
||||||
|
l_carry = (l_sum < *p_product.offset(i as isize)) as libc::c_int as uint64_t
|
||||||
|
}
|
||||||
|
*p_product.offset(i as isize) = l_sum;
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while vli_cmp(p_product, curve_p.as_mut_ptr()) > 0 as libc::c_int {
|
||||||
|
vli_sub(p_product, p_product, curve_p.as_mut_ptr());
|
||||||
|
}
|
||||||
|
vli_set(p_result, p_product);
|
||||||
|
}
|
||||||
|
//#endif
|
||||||
|
/* Computes p_result = (p_left * p_right) % curve_p. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_modMult_fast(mut p_result: *mut uint64_t, mut p_left: *mut uint64_t, mut p_right: *mut uint64_t) {
|
||||||
|
let mut l_product: [uint64_t; 12] = [0; 12];
|
||||||
|
vli_mult(l_product.as_mut_ptr(), p_left, p_right);
|
||||||
|
vli_mmod_fast(p_result, l_product.as_mut_ptr());
|
||||||
|
}
|
||||||
|
/* Computes p_result = p_left^2 % curve_p. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_modSquare_fast(mut p_result: *mut uint64_t, mut p_left: *mut uint64_t) {
|
||||||
|
let mut l_product: [uint64_t; 12] = [0; 12];
|
||||||
|
vli_square(l_product.as_mut_ptr(), p_left);
|
||||||
|
vli_mmod_fast(p_result, l_product.as_mut_ptr());
|
||||||
|
}
|
||||||
|
/* Computes p_result = (1 / p_input) % p_mod. All VLIs are the same size.
|
||||||
|
See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
|
||||||
|
https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_modInv(mut p_result: *mut uint64_t, mut p_input: *mut uint64_t, mut p_mod: *mut uint64_t) {
|
||||||
|
let mut a: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut b: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut u: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut v: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut l_carry: uint64_t = 0;
|
||||||
|
let mut l_cmpResult: libc::c_int = 0;
|
||||||
|
if vli_isZero(p_input) != 0 {
|
||||||
|
vli_clear(p_result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vli_set(a.as_mut_ptr(), p_input);
|
||||||
|
vli_set(b.as_mut_ptr(), p_mod);
|
||||||
|
vli_clear(u.as_mut_ptr());
|
||||||
|
u[0 as libc::c_int as usize] = 1 as libc::c_int as uint64_t;
|
||||||
|
vli_clear(v.as_mut_ptr());
|
||||||
|
loop {
|
||||||
|
l_cmpResult = vli_cmp(a.as_mut_ptr(), b.as_mut_ptr());
|
||||||
|
if !(l_cmpResult != 0 as libc::c_int) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
l_carry = 0 as libc::c_int as uint64_t;
|
||||||
|
if a[0 as libc::c_int as usize] & 1 as libc::c_int as libc::c_ulong == 0 {
|
||||||
|
vli_rshift1(a.as_mut_ptr());
|
||||||
|
if u[0 as libc::c_int as usize] & 1 as libc::c_int as libc::c_ulong != 0 {
|
||||||
|
l_carry = vli_add(u.as_mut_ptr(), u.as_mut_ptr(), p_mod)
|
||||||
|
}
|
||||||
|
vli_rshift1(u.as_mut_ptr());
|
||||||
|
if l_carry != 0 {
|
||||||
|
u[(48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as usize] = (u[(48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as usize] as libc::c_ulonglong | 0x8000000000000000 as libc::c_ulonglong) as uint64_t
|
||||||
|
}
|
||||||
|
} else if b[0 as libc::c_int as usize] & 1 as libc::c_int as libc::c_ulong == 0 {
|
||||||
|
vli_rshift1(b.as_mut_ptr());
|
||||||
|
if v[0 as libc::c_int as usize] & 1 as libc::c_int as libc::c_ulong != 0 {
|
||||||
|
l_carry = vli_add(v.as_mut_ptr(), v.as_mut_ptr(), p_mod)
|
||||||
|
}
|
||||||
|
vli_rshift1(v.as_mut_ptr());
|
||||||
|
if l_carry != 0 {
|
||||||
|
v[(48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as usize] = (v[(48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as usize] as libc::c_ulonglong | 0x8000000000000000 as libc::c_ulonglong) as uint64_t
|
||||||
|
}
|
||||||
|
} else if l_cmpResult > 0 as libc::c_int {
|
||||||
|
vli_sub(a.as_mut_ptr(), a.as_mut_ptr(), b.as_mut_ptr());
|
||||||
|
vli_rshift1(a.as_mut_ptr());
|
||||||
|
if vli_cmp(u.as_mut_ptr(), v.as_mut_ptr()) < 0 as libc::c_int {
|
||||||
|
vli_add(u.as_mut_ptr(), u.as_mut_ptr(), p_mod);
|
||||||
|
}
|
||||||
|
vli_sub(u.as_mut_ptr(), u.as_mut_ptr(), v.as_mut_ptr());
|
||||||
|
if u[0 as libc::c_int as usize] & 1 as libc::c_int as libc::c_ulong != 0 {
|
||||||
|
l_carry = vli_add(u.as_mut_ptr(), u.as_mut_ptr(), p_mod)
|
||||||
|
}
|
||||||
|
vli_rshift1(u.as_mut_ptr());
|
||||||
|
if l_carry != 0 {
|
||||||
|
u[(48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as usize] = (u[(48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as usize] as libc::c_ulonglong | 0x8000000000000000 as libc::c_ulonglong) as uint64_t
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vli_sub(b.as_mut_ptr(), b.as_mut_ptr(), a.as_mut_ptr());
|
||||||
|
vli_rshift1(b.as_mut_ptr());
|
||||||
|
if vli_cmp(v.as_mut_ptr(), u.as_mut_ptr()) < 0 as libc::c_int {
|
||||||
|
vli_add(v.as_mut_ptr(), v.as_mut_ptr(), p_mod);
|
||||||
|
}
|
||||||
|
vli_sub(v.as_mut_ptr(), v.as_mut_ptr(), u.as_mut_ptr());
|
||||||
|
if v[0 as libc::c_int as usize] & 1 as libc::c_int as libc::c_ulong != 0 {
|
||||||
|
l_carry = vli_add(v.as_mut_ptr(), v.as_mut_ptr(), p_mod)
|
||||||
|
}
|
||||||
|
vli_rshift1(v.as_mut_ptr());
|
||||||
|
if l_carry != 0 {
|
||||||
|
v[(48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as usize] = (v[(48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as usize] as libc::c_ulonglong | 0x8000000000000000 as libc::c_ulonglong) as uint64_t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vli_set(p_result, u.as_mut_ptr());
|
||||||
|
}
|
||||||
|
/* ------ Point operations ------ */
|
||||||
|
/* Returns 1 if p_point is the point at infinity, 0 otherwise. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn EccPoint_isZero(mut p_point: *mut EccPoint) -> libc::c_int {
|
||||||
|
return (vli_isZero((*p_point).x.as_mut_ptr()) != 0 && vli_isZero((*p_point).y.as_mut_ptr()) != 0) as libc::c_int;
|
||||||
|
}
|
||||||
|
/* Point multiplication algorithm using Montgomery's ladder with co-Z coordinates.
|
||||||
|
From http://eprint.iacr.org/2011/338.pdf
|
||||||
|
*/
|
||||||
|
/* Double in place */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn EccPoint_double_jacobian(mut X1: *mut uint64_t, mut Y1: *mut uint64_t, mut Z1: *mut uint64_t) {
|
||||||
|
/* t1 = X, t2 = Y, t3 = Z */
|
||||||
|
let mut t4: [uint64_t; 6] = [0; 6]; /* t4 = y1^2 */
|
||||||
|
let mut t5: [uint64_t; 6] = [0; 6]; /* t5 = x1*y1^2 = A */
|
||||||
|
if vli_isZero(Z1) != 0 {
|
||||||
|
return;
|
||||||
|
} /* t4 = y1^4 */
|
||||||
|
vli_modSquare_fast(t4.as_mut_ptr(), Y1); /* t2 = y1*z1 = z3 */
|
||||||
|
vli_modMult_fast(t5.as_mut_ptr(), X1, t4.as_mut_ptr()); /* t3 = z1^2 */
|
||||||
|
vli_modSquare_fast(t4.as_mut_ptr(), t4.as_mut_ptr()); /* t1 = x1 + z1^2 */
|
||||||
|
vli_modMult_fast(Y1, Y1, Z1); /* t3 = 2*z1^2 */
|
||||||
|
vli_modSquare_fast(Z1, Z1); /* t3 = x1 - z1^2 */
|
||||||
|
vli_modAdd(X1, X1, Z1, curve_p.as_mut_ptr()); /* t1 = x1^2 - z1^4 */
|
||||||
|
vli_modAdd(Z1, Z1, Z1, curve_p.as_mut_ptr()); /* t3 = 2*(x1^2 - z1^4) */
|
||||||
|
vli_modSub(Z1, X1, Z1, curve_p.as_mut_ptr()); /* t1 = 3*(x1^2 - z1^4) */
|
||||||
|
vli_modMult_fast(X1, X1, Z1);
|
||||||
|
vli_modAdd(Z1, X1, X1, curve_p.as_mut_ptr());
|
||||||
|
vli_modAdd(X1, X1, Z1, curve_p.as_mut_ptr());
|
||||||
|
if vli_testBit(X1, 0 as libc::c_int as uint) != 0 {
|
||||||
|
let mut l_carry: uint64_t = vli_add(X1, X1, curve_p.as_mut_ptr());
|
||||||
|
vli_rshift1(X1);
|
||||||
|
let ref mut fresh2 = *X1.offset((48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as isize);
|
||||||
|
*fresh2 |= l_carry << 63 as libc::c_int
|
||||||
|
} else {
|
||||||
|
vli_rshift1(X1);
|
||||||
|
}
|
||||||
|
/* t1 = 3/2*(x1^2 - z1^4) = B */
|
||||||
|
vli_modSquare_fast(Z1, X1); /* t3 = B^2 */
|
||||||
|
vli_modSub(Z1, Z1, t5.as_mut_ptr(), curve_p.as_mut_ptr()); /* t3 = B^2 - A */
|
||||||
|
vli_modSub(Z1, Z1, t5.as_mut_ptr(), curve_p.as_mut_ptr()); /* t3 = B^2 - 2A = x3 */
|
||||||
|
vli_modSub(t5.as_mut_ptr(), t5.as_mut_ptr(), Z1, curve_p.as_mut_ptr()); /* t5 = A - x3 */
|
||||||
|
vli_modMult_fast(X1, X1, t5.as_mut_ptr()); /* t1 = B * (A - x3) */
|
||||||
|
vli_modSub(t4.as_mut_ptr(), X1, t4.as_mut_ptr(), curve_p.as_mut_ptr()); /* t4 = B * (A - x3) - y1^4 = y3 */
|
||||||
|
vli_set(X1, Z1);
|
||||||
|
vli_set(Z1, Y1);
|
||||||
|
vli_set(Y1, t4.as_mut_ptr());
|
||||||
|
}
|
||||||
|
/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn apply_z(mut X1: *mut uint64_t, mut Y1: *mut uint64_t, mut Z: *mut uint64_t) {
|
||||||
|
let mut t1: [uint64_t; 6] = [0; 6]; /* z^2 */
|
||||||
|
vli_modSquare_fast(t1.as_mut_ptr(), Z); /* x1 * z^2 */
|
||||||
|
vli_modMult_fast(X1, X1, t1.as_mut_ptr()); /* z^3 */
|
||||||
|
vli_modMult_fast(t1.as_mut_ptr(), t1.as_mut_ptr(), Z);
|
||||||
|
vli_modMult_fast(Y1, Y1, t1.as_mut_ptr());
|
||||||
|
/* y1 * z^3 */
|
||||||
|
}
|
||||||
|
/* P = (x1, y1) => 2P, (x2, y2) => P' */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn XYcZ_initial_double(mut X1: *mut uint64_t, mut Y1: *mut uint64_t, mut X2: *mut uint64_t, mut Y2: *mut uint64_t, mut p_initialZ: *mut uint64_t) {
|
||||||
|
let mut z: [uint64_t; 6] = [0; 6];
|
||||||
|
vli_set(X2, X1);
|
||||||
|
vli_set(Y2, Y1);
|
||||||
|
vli_clear(z.as_mut_ptr());
|
||||||
|
z[0 as libc::c_int as usize] = 1 as libc::c_int as uint64_t;
|
||||||
|
if !p_initialZ.is_null() {
|
||||||
|
vli_set(z.as_mut_ptr(), p_initialZ);
|
||||||
|
}
|
||||||
|
apply_z(X1, Y1, z.as_mut_ptr());
|
||||||
|
EccPoint_double_jacobian(X1, Y1, z.as_mut_ptr());
|
||||||
|
apply_z(X2, Y2, z.as_mut_ptr());
|
||||||
|
}
|
||||||
|
/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
|
||||||
|
Output P' = (x1', y1', Z3), P + Q = (x3, y3, Z3)
|
||||||
|
or P => P', Q => P + Q
|
||||||
|
*/
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn XYcZ_add(mut X1: *mut uint64_t, mut Y1: *mut uint64_t, mut X2: *mut uint64_t, mut Y2: *mut uint64_t) {
|
||||||
|
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
|
||||||
|
let mut t5: [uint64_t; 6] = [0; 6]; /* t5 = x2 - x1 */
|
||||||
|
vli_modSub(t5.as_mut_ptr(), X2, X1, curve_p.as_mut_ptr()); /* t5 = (x2 - x1)^2 = A */
|
||||||
|
vli_modSquare_fast(t5.as_mut_ptr(), t5.as_mut_ptr()); /* t1 = x1*A = B */
|
||||||
|
vli_modMult_fast(X1, X1, t5.as_mut_ptr()); /* t3 = x2*A = C */
|
||||||
|
vli_modMult_fast(X2, X2, t5.as_mut_ptr()); /* t4 = y2 - y1 */
|
||||||
|
vli_modSub(Y2, Y2, Y1, curve_p.as_mut_ptr()); /* t5 = (y2 - y1)^2 = D */
|
||||||
|
vli_modSquare_fast(t5.as_mut_ptr(), Y2); /* t5 = D - B */
|
||||||
|
vli_modSub(t5.as_mut_ptr(), t5.as_mut_ptr(), X1, curve_p.as_mut_ptr()); /* t5 = D - B - C = x3 */
|
||||||
|
vli_modSub(t5.as_mut_ptr(), t5.as_mut_ptr(), X2, curve_p.as_mut_ptr()); /* t3 = C - B */
|
||||||
|
vli_modSub(X2, X2, X1, curve_p.as_mut_ptr()); /* t2 = y1*(C - B) */
|
||||||
|
vli_modMult_fast(Y1, Y1, X2); /* t3 = B - x3 */
|
||||||
|
vli_modSub(X2, X1, t5.as_mut_ptr(), curve_p.as_mut_ptr()); /* t4 = (y2 - y1)*(B - x3) */
|
||||||
|
vli_modMult_fast(Y2, Y2, X2); /* t4 = y3 */
|
||||||
|
vli_modSub(Y2, Y2, Y1, curve_p.as_mut_ptr());
|
||||||
|
vli_set(X2, t5.as_mut_ptr());
|
||||||
|
}
|
||||||
|
/* Input P = (x1, y1, Z), Q = (x2, y2, Z)
|
||||||
|
Output P + Q = (x3, y3, Z3), P - Q = (x3', y3', Z3)
|
||||||
|
or P => P - Q, Q => P + Q
|
||||||
|
*/
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn XYcZ_addC(mut X1: *mut uint64_t, mut Y1: *mut uint64_t, mut X2: *mut uint64_t, mut Y2: *mut uint64_t) {
|
||||||
|
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
|
||||||
|
let mut t5: [uint64_t; 6] = [0; 6]; /* t5 = x2 - x1 */
|
||||||
|
let mut t6: [uint64_t; 6] = [0; 6]; /* t5 = (x2 - x1)^2 = A */
|
||||||
|
let mut t7: [uint64_t; 6] = [0; 6]; /* t1 = x1*A = B */
|
||||||
|
vli_modSub(t5.as_mut_ptr(), X2, X1, curve_p.as_mut_ptr()); /* t3 = x2*A = C */
|
||||||
|
vli_modSquare_fast(t5.as_mut_ptr(), t5.as_mut_ptr()); /* t4 = y2 + y1 */
|
||||||
|
vli_modMult_fast(X1, X1, t5.as_mut_ptr()); /* t4 = y2 - y1 */
|
||||||
|
vli_modMult_fast(X2, X2, t5.as_mut_ptr()); /* t6 = C - B */
|
||||||
|
vli_modAdd(t5.as_mut_ptr(), Y2, Y1, curve_p.as_mut_ptr()); /* t2 = y1 * (C - B) */
|
||||||
|
vli_modSub(Y2, Y2, Y1, curve_p.as_mut_ptr()); /* t6 = B + C */
|
||||||
|
vli_modSub(t6.as_mut_ptr(), X2, X1, curve_p.as_mut_ptr()); /* t3 = (y2 - y1)^2 */
|
||||||
|
vli_modMult_fast(Y1, Y1, t6.as_mut_ptr()); /* t3 = x3 */
|
||||||
|
vli_modAdd(t6.as_mut_ptr(), X1, X2, curve_p.as_mut_ptr()); /* t7 = B - x3 */
|
||||||
|
vli_modSquare_fast(X2, Y2); /* t4 = (y2 - y1)*(B - x3) */
|
||||||
|
vli_modSub(X2, X2, t6.as_mut_ptr(), curve_p.as_mut_ptr()); /* t4 = y3 */
|
||||||
|
vli_modSub(t7.as_mut_ptr(), X1, X2, curve_p.as_mut_ptr()); /* t7 = (y2 + y1)^2 = F */
|
||||||
|
vli_modMult_fast(Y2, Y2, t7.as_mut_ptr()); /* t7 = x3' */
|
||||||
|
vli_modSub(Y2, Y2, Y1, curve_p.as_mut_ptr()); /* t6 = x3' - B */
|
||||||
|
vli_modSquare_fast(t7.as_mut_ptr(), t5.as_mut_ptr()); /* t6 = (y2 + y1)*(x3' - B) */
|
||||||
|
vli_modSub(t7.as_mut_ptr(), t7.as_mut_ptr(), t6.as_mut_ptr(), curve_p.as_mut_ptr()); /* t2 = y3' */
|
||||||
|
vli_modSub(t6.as_mut_ptr(), t7.as_mut_ptr(), X1, curve_p.as_mut_ptr());
|
||||||
|
vli_modMult_fast(t6.as_mut_ptr(), t6.as_mut_ptr(), t5.as_mut_ptr());
|
||||||
|
vli_modSub(Y1, t6.as_mut_ptr(), Y1, curve_p.as_mut_ptr());
|
||||||
|
vli_set(X1, t7.as_mut_ptr());
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn EccPoint_mult(mut p_result: *mut EccPoint, mut p_point: *mut EccPoint, mut p_scalar: *mut uint64_t, mut p_initialZ: *mut uint64_t) {
|
||||||
|
/* R0 and R1 */
|
||||||
|
let mut Rx: [[uint64_t; 6]; 2] = [[0; 6]; 2];
|
||||||
|
let mut Ry: [[uint64_t; 6]; 2] = [[0; 6]; 2];
|
||||||
|
let mut z: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut i: libc::c_int = 0;
|
||||||
|
let mut nb: libc::c_int = 0;
|
||||||
|
vli_set(Rx[1 as libc::c_int as usize].as_mut_ptr(), (*p_point).x.as_mut_ptr());
|
||||||
|
vli_set(Ry[1 as libc::c_int as usize].as_mut_ptr(), (*p_point).y.as_mut_ptr());
|
||||||
|
XYcZ_initial_double(
|
||||||
|
Rx[1 as libc::c_int as usize].as_mut_ptr(),
|
||||||
|
Ry[1 as libc::c_int as usize].as_mut_ptr(),
|
||||||
|
Rx[0 as libc::c_int as usize].as_mut_ptr(),
|
||||||
|
Ry[0 as libc::c_int as usize].as_mut_ptr(),
|
||||||
|
p_initialZ,
|
||||||
|
);
|
||||||
|
i = vli_numBits(p_scalar).wrapping_sub(2 as libc::c_int as libc::c_uint) as libc::c_int;
|
||||||
|
while i > 0 as libc::c_int {
|
||||||
|
nb = (vli_testBit(p_scalar, i as uint) == 0) as libc::c_int;
|
||||||
|
XYcZ_addC(Rx[(1 as libc::c_int - nb) as usize].as_mut_ptr(), Ry[(1 as libc::c_int - nb) as usize].as_mut_ptr(), Rx[nb as usize].as_mut_ptr(), Ry[nb as usize].as_mut_ptr());
|
||||||
|
XYcZ_add(Rx[nb as usize].as_mut_ptr(), Ry[nb as usize].as_mut_ptr(), Rx[(1 as libc::c_int - nb) as usize].as_mut_ptr(), Ry[(1 as libc::c_int - nb) as usize].as_mut_ptr());
|
||||||
|
i -= 1
|
||||||
|
}
|
||||||
|
nb = (vli_testBit(p_scalar, 0 as libc::c_int as uint) == 0) as libc::c_int;
|
||||||
|
XYcZ_addC(Rx[(1 as libc::c_int - nb) as usize].as_mut_ptr(), Ry[(1 as libc::c_int - nb) as usize].as_mut_ptr(), Rx[nb as usize].as_mut_ptr(), Ry[nb as usize].as_mut_ptr());
|
||||||
|
/* Find final 1/Z value. */
|
||||||
|
vli_modSub(z.as_mut_ptr(), Rx[1 as libc::c_int as usize].as_mut_ptr(), Rx[0 as libc::c_int as usize].as_mut_ptr(), curve_p.as_mut_ptr()); /* X1 - X0 */
|
||||||
|
vli_modMult_fast(z.as_mut_ptr(), z.as_mut_ptr(), Ry[(1 as libc::c_int - nb) as usize].as_mut_ptr()); /* Yb * (X1 - X0) */
|
||||||
|
vli_modMult_fast(z.as_mut_ptr(), z.as_mut_ptr(), (*p_point).x.as_mut_ptr()); /* xP * Yb * (X1 - X0) */
|
||||||
|
vli_modInv(z.as_mut_ptr(), z.as_mut_ptr(), curve_p.as_mut_ptr()); /* 1 / (xP * Yb * (X1 - X0)) */
|
||||||
|
vli_modMult_fast(z.as_mut_ptr(), z.as_mut_ptr(), (*p_point).y.as_mut_ptr()); /* yP / (xP * Yb * (X1 - X0)) */
|
||||||
|
vli_modMult_fast(z.as_mut_ptr(), z.as_mut_ptr(), Rx[(1 as libc::c_int - nb) as usize].as_mut_ptr()); /* Xb * yP / (xP * Yb * (X1 - X0)) */
|
||||||
|
/* End 1/Z calculation */
|
||||||
|
XYcZ_add(Rx[nb as usize].as_mut_ptr(), Ry[nb as usize].as_mut_ptr(), Rx[(1 as libc::c_int - nb) as usize].as_mut_ptr(), Ry[(1 as libc::c_int - nb) as usize].as_mut_ptr());
|
||||||
|
apply_z(Rx[0 as libc::c_int as usize].as_mut_ptr(), Ry[0 as libc::c_int as usize].as_mut_ptr(), z.as_mut_ptr());
|
||||||
|
vli_set((*p_result).x.as_mut_ptr(), Rx[0 as libc::c_int as usize].as_mut_ptr());
|
||||||
|
vli_set((*p_result).y.as_mut_ptr(), Ry[0 as libc::c_int as usize].as_mut_ptr());
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn ecc_bytes2native(mut p_native: *mut uint64_t, mut p_bytes: *const uint8_t) {
|
||||||
|
let mut i: libc::c_uint = 0;
|
||||||
|
i = 0 as libc::c_int as libc::c_uint;
|
||||||
|
while i < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
let mut p_digit: *const uint8_t = p_bytes.offset((8 as libc::c_int as libc::c_uint).wrapping_mul(((48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as libc::c_uint).wrapping_sub(i)) as isize);
|
||||||
|
*p_native.offset(i as isize) = (*p_digit.offset(0 as libc::c_int as isize) as uint64_t) << 56 as libc::c_int
|
||||||
|
| (*p_digit.offset(1 as libc::c_int as isize) as uint64_t) << 48 as libc::c_int
|
||||||
|
| (*p_digit.offset(2 as libc::c_int as isize) as uint64_t) << 40 as libc::c_int
|
||||||
|
| (*p_digit.offset(3 as libc::c_int as isize) as uint64_t) << 32 as libc::c_int
|
||||||
|
| (*p_digit.offset(4 as libc::c_int as isize) as uint64_t) << 24 as libc::c_int
|
||||||
|
| (*p_digit.offset(5 as libc::c_int as isize) as uint64_t) << 16 as libc::c_int
|
||||||
|
| (*p_digit.offset(6 as libc::c_int as isize) as uint64_t) << 8 as libc::c_int
|
||||||
|
| *p_digit.offset(7 as libc::c_int as isize) as uint64_t;
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn ecc_native2bytes(mut p_bytes: *mut uint8_t, mut p_native: *const uint64_t) {
|
||||||
|
let mut i: libc::c_uint = 0;
|
||||||
|
i = 0 as libc::c_int as libc::c_uint;
|
||||||
|
while i < (48 as libc::c_int / 8 as libc::c_int) as libc::c_uint {
|
||||||
|
let mut p_digit: *mut uint8_t = p_bytes.offset((8 as libc::c_int as libc::c_uint).wrapping_mul(((48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as libc::c_uint).wrapping_sub(i)) as isize);
|
||||||
|
*p_digit.offset(0 as libc::c_int as isize) = (*p_native.offset(i as isize) >> 56 as libc::c_int) as uint8_t;
|
||||||
|
*p_digit.offset(1 as libc::c_int as isize) = (*p_native.offset(i as isize) >> 48 as libc::c_int) as uint8_t;
|
||||||
|
*p_digit.offset(2 as libc::c_int as isize) = (*p_native.offset(i as isize) >> 40 as libc::c_int) as uint8_t;
|
||||||
|
*p_digit.offset(3 as libc::c_int as isize) = (*p_native.offset(i as isize) >> 32 as libc::c_int) as uint8_t;
|
||||||
|
*p_digit.offset(4 as libc::c_int as isize) = (*p_native.offset(i as isize) >> 24 as libc::c_int) as uint8_t;
|
||||||
|
*p_digit.offset(5 as libc::c_int as isize) = (*p_native.offset(i as isize) >> 16 as libc::c_int) as uint8_t;
|
||||||
|
*p_digit.offset(6 as libc::c_int as isize) = (*p_native.offset(i as isize) >> 8 as libc::c_int) as uint8_t;
|
||||||
|
*p_digit.offset(7 as libc::c_int as isize) = *p_native.offset(i as isize) as uint8_t;
|
||||||
|
i = i.wrapping_add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Compute a = sqrt(a) (mod curve_p). */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn mod_sqrt(mut a: *mut uint64_t) {
|
||||||
|
let mut i: libc::c_uint = 0;
|
||||||
|
let mut p1: [uint64_t; 6] = [1 as libc::c_int as uint64_t, 0, 0, 0, 0, 0];
|
||||||
|
let mut l_result: [uint64_t; 6] = [1 as libc::c_int as uint64_t, 0, 0, 0, 0, 0];
|
||||||
|
/* Since curve_p == 3 (mod 4) for all supported curves, we can
|
||||||
|
compute sqrt(a) = a^((curve_p + 1) / 4) (mod curve_p). */
|
||||||
|
vli_add(p1.as_mut_ptr(), curve_p.as_mut_ptr(), p1.as_mut_ptr()); /* p1 = curve_p + 1 */
|
||||||
|
i = vli_numBits(p1.as_mut_ptr()).wrapping_sub(1 as libc::c_int as libc::c_uint); /* -a = 3 */
|
||||||
|
while i > 1 as libc::c_int as libc::c_uint {
|
||||||
|
vli_modSquare_fast(l_result.as_mut_ptr(), l_result.as_mut_ptr()); /* y = x^2 */
|
||||||
|
if vli_testBit(p1.as_mut_ptr(), i) != 0 {
|
||||||
|
vli_modMult_fast(l_result.as_mut_ptr(), l_result.as_mut_ptr(), a); /* y = x^2 - 3 */
|
||||||
|
} /* y = x^3 - 3x */
|
||||||
|
i = i.wrapping_sub(1)
|
||||||
|
} /* y = x^3 - 3x + b */
|
||||||
|
vli_set(a, l_result.as_mut_ptr());
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn ecc_point_decompress(mut p_point: *mut EccPoint, mut p_compressed: *const uint8_t) {
|
||||||
|
let mut _3: [uint64_t; 6] = [3 as libc::c_int as uint64_t, 0, 0, 0, 0, 0];
|
||||||
|
ecc_bytes2native((*p_point).x.as_mut_ptr(), p_compressed.offset(1 as libc::c_int as isize));
|
||||||
|
vli_modSquare_fast((*p_point).y.as_mut_ptr(), (*p_point).x.as_mut_ptr());
|
||||||
|
vli_modSub((*p_point).y.as_mut_ptr(), (*p_point).y.as_mut_ptr(), _3.as_mut_ptr(), curve_p.as_mut_ptr());
|
||||||
|
vli_modMult_fast((*p_point).y.as_mut_ptr(), (*p_point).y.as_mut_ptr(), (*p_point).x.as_mut_ptr());
|
||||||
|
vli_modAdd((*p_point).y.as_mut_ptr(), (*p_point).y.as_mut_ptr(), curve_b.as_mut_ptr(), curve_p.as_mut_ptr());
|
||||||
|
mod_sqrt((*p_point).y.as_mut_ptr());
|
||||||
|
if (*p_point).y[0 as libc::c_int as usize] & 0x1 as libc::c_int as libc::c_ulong != (*p_compressed.offset(0 as libc::c_int as isize) as libc::c_int & 0x1 as libc::c_int) as libc::c_ulong {
|
||||||
|
vli_sub((*p_point).y.as_mut_ptr(), curve_p.as_mut_ptr(), (*p_point).y.as_mut_ptr());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub unsafe fn ecc_make_key(mut p_publicKey: *mut uint8_t, mut p_privateKey: *mut uint8_t) -> libc::c_int {
|
||||||
|
let mut l_private: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut l_public: EccPoint = EccPoint { x: [0; 6], y: [0; 6] };
|
||||||
|
let mut l_tries: libc::c_uint = 0 as libc::c_int as libc::c_uint;
|
||||||
|
loop {
|
||||||
|
if getRandomNumber(l_private.as_mut_ptr()) == 0 || {
|
||||||
|
let fresh3 = l_tries;
|
||||||
|
l_tries = l_tries.wrapping_add(1);
|
||||||
|
(fresh3) >= 1024 as libc::c_int as libc::c_uint
|
||||||
|
} {
|
||||||
|
return 0 as libc::c_int;
|
||||||
|
}
|
||||||
|
if !(vli_isZero(l_private.as_mut_ptr()) != 0) {
|
||||||
|
/* Make sure the private key is in the range [1, n-1].
|
||||||
|
For the supported curves, n is always large enough that we only need to subtract once at most. */
|
||||||
|
if vli_cmp(curve_n.as_mut_ptr(), l_private.as_mut_ptr()) != 1 as libc::c_int {
|
||||||
|
vli_sub(l_private.as_mut_ptr(), l_private.as_mut_ptr(), curve_n.as_mut_ptr());
|
||||||
|
}
|
||||||
|
EccPoint_mult(&mut l_public, &mut curve_G, l_private.as_mut_ptr(), 0 as *mut uint64_t);
|
||||||
|
}
|
||||||
|
if !(EccPoint_isZero(&mut l_public) != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ecc_native2bytes(p_privateKey, l_private.as_mut_ptr() as *const uint64_t);
|
||||||
|
ecc_native2bytes(p_publicKey.offset(1 as libc::c_int as isize), l_public.x.as_mut_ptr() as *const uint64_t);
|
||||||
|
*p_publicKey.offset(0 as libc::c_int as isize) = (2 as libc::c_int as libc::c_ulong).wrapping_add(l_public.y[0 as libc::c_int as usize] & 0x1 as libc::c_int as libc::c_ulong) as uint8_t;
|
||||||
|
return 1 as libc::c_int;
|
||||||
|
}
|
||||||
|
pub unsafe fn ecdh_shared_secret(mut p_publicKey: *const uint8_t, mut p_privateKey: *const uint8_t, mut p_secret: *mut uint8_t) -> libc::c_int {
|
||||||
|
let mut l_public: EccPoint = EccPoint { x: [0; 6], y: [0; 6] };
|
||||||
|
let mut l_private: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut l_random: [uint64_t; 6] = [0; 6];
|
||||||
|
if getRandomNumber(l_random.as_mut_ptr()) == 0 {
|
||||||
|
return 0 as libc::c_int;
|
||||||
|
}
|
||||||
|
ecc_point_decompress(&mut l_public, p_publicKey);
|
||||||
|
ecc_bytes2native(l_private.as_mut_ptr(), p_privateKey);
|
||||||
|
let mut l_product: EccPoint = EccPoint { x: [0; 6], y: [0; 6] };
|
||||||
|
EccPoint_mult(&mut l_product, &mut l_public, l_private.as_mut_ptr(), l_random.as_mut_ptr());
|
||||||
|
ecc_native2bytes(p_secret, l_product.x.as_mut_ptr() as *const uint64_t);
|
||||||
|
return (EccPoint_isZero(&mut l_product) == 0) as libc::c_int;
|
||||||
|
}
|
||||||
|
/* -------- ECDSA code -------- */
|
||||||
|
/* Computes p_result = (p_left * p_right) % p_mod. */
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn vli_modMult(mut p_result: *mut uint64_t, mut p_left: *mut uint64_t, mut p_right: *mut uint64_t, mut p_mod: *mut uint64_t) {
|
||||||
|
let mut l_product: [uint64_t; 12] = [0; 12];
|
||||||
|
let mut l_modMultiple: [uint64_t; 12] = [0; 12];
|
||||||
|
let mut l_digitShift: uint = 0;
|
||||||
|
let mut l_bitShift: uint = 0;
|
||||||
|
let mut l_productBits: uint = 0;
|
||||||
|
let mut l_modBits: uint = vli_numBits(p_mod);
|
||||||
|
vli_mult(l_product.as_mut_ptr(), p_left, p_right);
|
||||||
|
l_productBits = vli_numBits(l_product.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize));
|
||||||
|
if l_productBits != 0 {
|
||||||
|
l_productBits = (l_productBits as libc::c_uint).wrapping_add((48 as libc::c_int / 8 as libc::c_int * 64 as libc::c_int) as libc::c_uint) as uint as uint
|
||||||
|
} else {
|
||||||
|
l_productBits = vli_numBits(l_product.as_mut_ptr())
|
||||||
|
}
|
||||||
|
if l_productBits < l_modBits {
|
||||||
|
/* l_product < p_mod. */
|
||||||
|
vli_set(p_result, l_product.as_mut_ptr());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* Shift p_mod by (l_leftBits - l_modBits). This multiplies p_mod by the largest
|
||||||
|
power of two possible while still resulting in a number less than p_left. */
|
||||||
|
vli_clear(l_modMultiple.as_mut_ptr());
|
||||||
|
vli_clear(l_modMultiple.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize));
|
||||||
|
l_digitShift = l_productBits.wrapping_sub(l_modBits).wrapping_div(64 as libc::c_int as libc::c_uint);
|
||||||
|
l_bitShift = l_productBits.wrapping_sub(l_modBits).wrapping_rem(64 as libc::c_int as libc::c_uint);
|
||||||
|
if l_bitShift != 0 {
|
||||||
|
l_modMultiple[l_digitShift.wrapping_add((48 as libc::c_int / 8 as libc::c_int) as libc::c_uint) as usize] = vli_lshift(l_modMultiple.as_mut_ptr().offset(l_digitShift as isize), p_mod, l_bitShift)
|
||||||
|
} else {
|
||||||
|
vli_set(l_modMultiple.as_mut_ptr().offset(l_digitShift as isize), p_mod);
|
||||||
|
}
|
||||||
|
/* Subtract all multiples of p_mod to get the remainder. */
|
||||||
|
vli_clear(p_result); /* Use p_result as a temp var to store 1 (for subtraction) */
|
||||||
|
*p_result.offset(0 as libc::c_int as isize) = 1 as libc::c_int as uint64_t;
|
||||||
|
while l_productBits > (48 as libc::c_int / 8 as libc::c_int * 64 as libc::c_int) as libc::c_uint || vli_cmp(l_modMultiple.as_mut_ptr(), p_mod) >= 0 as libc::c_int {
|
||||||
|
let mut l_cmp: libc::c_int = vli_cmp(l_modMultiple.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize), l_product.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize));
|
||||||
|
if l_cmp < 0 as libc::c_int || l_cmp == 0 as libc::c_int && vli_cmp(l_modMultiple.as_mut_ptr(), l_product.as_mut_ptr()) <= 0 as libc::c_int {
|
||||||
|
if vli_sub(l_product.as_mut_ptr(), l_product.as_mut_ptr(), l_modMultiple.as_mut_ptr()) != 0 {
|
||||||
|
/* borrow */
|
||||||
|
vli_sub(l_product.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize), l_product.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize), p_result);
|
||||||
|
}
|
||||||
|
vli_sub(
|
||||||
|
l_product.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize),
|
||||||
|
l_product.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize),
|
||||||
|
l_modMultiple.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let mut l_carry: uint64_t = (l_modMultiple[(48 as libc::c_int / 8 as libc::c_int) as usize] & 0x1 as libc::c_int as libc::c_ulong) << 63 as libc::c_int;
|
||||||
|
vli_rshift1(l_modMultiple.as_mut_ptr().offset((48 as libc::c_int / 8 as libc::c_int) as isize));
|
||||||
|
vli_rshift1(l_modMultiple.as_mut_ptr());
|
||||||
|
l_modMultiple[(48 as libc::c_int / 8 as libc::c_int - 1 as libc::c_int) as usize] |= l_carry;
|
||||||
|
l_productBits = l_productBits.wrapping_sub(1)
|
||||||
|
}
|
||||||
|
vli_set(p_result, l_product.as_mut_ptr());
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn umax(mut a: uint, mut b: uint) -> uint {
|
||||||
|
return if a > b {
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
b
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub unsafe fn ecdsa_sign(mut p_privateKey: *const uint8_t, mut p_hash: *const uint8_t, mut p_signature: *mut uint8_t) -> libc::c_int {
|
||||||
|
let mut k: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut l_tmp: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut l_s: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut p: EccPoint = EccPoint { x: [0; 6], y: [0; 6] };
|
||||||
|
let mut l_tries: libc::c_uint = 0 as libc::c_int as libc::c_uint;
|
||||||
|
loop {
|
||||||
|
if getRandomNumber(k.as_mut_ptr()) == 0 || {
|
||||||
|
let fresh4 = l_tries;
|
||||||
|
l_tries = l_tries.wrapping_add(1);
|
||||||
|
(fresh4) >= 1024 as libc::c_int as libc::c_uint
|
||||||
|
} {
|
||||||
|
return 0 as libc::c_int;
|
||||||
|
}
|
||||||
|
if !(vli_isZero(k.as_mut_ptr()) != 0) {
|
||||||
|
if vli_cmp(curve_n.as_mut_ptr(), k.as_mut_ptr()) != 1 as libc::c_int {
|
||||||
|
vli_sub(k.as_mut_ptr(), k.as_mut_ptr(), curve_n.as_mut_ptr());
|
||||||
|
}
|
||||||
|
/* tmp = k * G */
|
||||||
|
EccPoint_mult(&mut p, &mut curve_G, k.as_mut_ptr(), 0 as *mut uint64_t);
|
||||||
|
/* r = x1 (mod n) */
|
||||||
|
if vli_cmp(curve_n.as_mut_ptr(), p.x.as_mut_ptr()) != 1 as libc::c_int {
|
||||||
|
vli_sub(p.x.as_mut_ptr(), p.x.as_mut_ptr(), curve_n.as_mut_ptr());
|
||||||
|
/* s = r*d */
|
||||||
|
}
|
||||||
|
} /* s = e + r*d */
|
||||||
|
if !(vli_isZero(p.x.as_mut_ptr()) != 0) {
|
||||||
|
break; /* k = 1 / k */
|
||||||
|
}
|
||||||
|
} /* s = (e + r*d) / k */
|
||||||
|
ecc_native2bytes(p_signature, p.x.as_mut_ptr() as *const uint64_t);
|
||||||
|
ecc_bytes2native(l_tmp.as_mut_ptr(), p_privateKey);
|
||||||
|
vli_modMult(l_s.as_mut_ptr(), p.x.as_mut_ptr(), l_tmp.as_mut_ptr(), curve_n.as_mut_ptr());
|
||||||
|
ecc_bytes2native(l_tmp.as_mut_ptr(), p_hash);
|
||||||
|
vli_modAdd(l_s.as_mut_ptr(), l_tmp.as_mut_ptr(), l_s.as_mut_ptr(), curve_n.as_mut_ptr());
|
||||||
|
vli_modInv(k.as_mut_ptr(), k.as_mut_ptr(), curve_n.as_mut_ptr());
|
||||||
|
vli_modMult(l_s.as_mut_ptr(), l_s.as_mut_ptr(), k.as_mut_ptr(), curve_n.as_mut_ptr());
|
||||||
|
ecc_native2bytes(p_signature.offset(48 as libc::c_int as isize), l_s.as_mut_ptr() as *const uint64_t);
|
||||||
|
return 1 as libc::c_int;
|
||||||
|
}
|
||||||
|
pub unsafe fn ecdsa_verify(mut p_publicKey: *const uint8_t, mut p_hash: *const uint8_t, mut p_signature: *const uint8_t) -> libc::c_int {
|
||||||
|
let mut u1: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut u2: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut z: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut l_public: EccPoint = EccPoint { x: [0; 6], y: [0; 6] };
|
||||||
|
let mut l_sum: EccPoint = EccPoint { x: [0; 6], y: [0; 6] };
|
||||||
|
let mut rx: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut ry: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut tx: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut ty: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut tz: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut l_r: [uint64_t; 6] = [0; 6];
|
||||||
|
let mut l_s: [uint64_t; 6] = [0; 6];
|
||||||
|
ecc_point_decompress(&mut l_public, p_publicKey);
|
||||||
|
ecc_bytes2native(l_r.as_mut_ptr(), p_signature);
|
||||||
|
ecc_bytes2native(l_s.as_mut_ptr(), p_signature.offset(48 as libc::c_int as isize));
|
||||||
|
if vli_isZero(l_r.as_mut_ptr()) != 0 || vli_isZero(l_s.as_mut_ptr()) != 0 {
|
||||||
|
/* r, s must not be 0. */
|
||||||
|
return 0 as libc::c_int;
|
||||||
|
}
|
||||||
|
if vli_cmp(curve_n.as_mut_ptr(), l_r.as_mut_ptr()) != 1 as libc::c_int || vli_cmp(curve_n.as_mut_ptr(), l_s.as_mut_ptr()) != 1 as libc::c_int {
|
||||||
|
/* r, s must be < n. */
|
||||||
|
return 0 as libc::c_int;
|
||||||
|
}
|
||||||
|
/* Calculate u1 and u2. */
|
||||||
|
vli_modInv(z.as_mut_ptr(), l_s.as_mut_ptr(), curve_n.as_mut_ptr()); /* Z = s^-1 */
|
||||||
|
ecc_bytes2native(u1.as_mut_ptr(), p_hash); /* u1 = e/s */
|
||||||
|
vli_modMult(u1.as_mut_ptr(), u1.as_mut_ptr(), z.as_mut_ptr(), curve_n.as_mut_ptr()); /* u2 = r/s */
|
||||||
|
vli_modMult(u2.as_mut_ptr(), l_r.as_mut_ptr(), z.as_mut_ptr(), curve_n.as_mut_ptr());
|
||||||
|
/* Calculate l_sum = G + Q. */
|
||||||
|
vli_set(l_sum.x.as_mut_ptr(), l_public.x.as_mut_ptr()); /* Z = x2 - x1 */
|
||||||
|
vli_set(l_sum.y.as_mut_ptr(), l_public.y.as_mut_ptr()); /* Z = 1/Z */
|
||||||
|
vli_set(tx.as_mut_ptr(), curve_G.x.as_mut_ptr());
|
||||||
|
vli_set(ty.as_mut_ptr(), curve_G.y.as_mut_ptr());
|
||||||
|
vli_modSub(z.as_mut_ptr(), l_sum.x.as_mut_ptr(), tx.as_mut_ptr(), curve_p.as_mut_ptr());
|
||||||
|
XYcZ_add(tx.as_mut_ptr(), ty.as_mut_ptr(), l_sum.x.as_mut_ptr(), l_sum.y.as_mut_ptr());
|
||||||
|
vli_modInv(z.as_mut_ptr(), z.as_mut_ptr(), curve_p.as_mut_ptr());
|
||||||
|
apply_z(l_sum.x.as_mut_ptr(), l_sum.y.as_mut_ptr(), z.as_mut_ptr());
|
||||||
|
/* Use Shamir's trick to calculate u1*G + u2*Q */
|
||||||
|
let mut l_points: [*mut EccPoint; 4] = [0 as *mut EccPoint, &mut curve_G, &mut l_public, &mut l_sum]; /* Z = x2 - x1 */
|
||||||
|
let mut l_numBits: uint = umax(vli_numBits(u1.as_mut_ptr()), vli_numBits(u2.as_mut_ptr())); /* Z = 1/Z */
|
||||||
|
let mut l_point: *mut EccPoint = l_points[((vli_testBit(u1.as_mut_ptr(), l_numBits.wrapping_sub(1 as libc::c_int as libc::c_uint)) != 0) as libc::c_int | ((vli_testBit(u2.as_mut_ptr(), l_numBits.wrapping_sub(1 as libc::c_int as libc::c_uint)) != 0) as libc::c_int) << 1 as libc::c_int) as usize];
|
||||||
|
vli_set(rx.as_mut_ptr(), (*l_point).x.as_mut_ptr());
|
||||||
|
vli_set(ry.as_mut_ptr(), (*l_point).y.as_mut_ptr());
|
||||||
|
vli_clear(z.as_mut_ptr());
|
||||||
|
z[0 as libc::c_int as usize] = 1 as libc::c_int as uint64_t;
|
||||||
|
let mut i: libc::c_int = 0;
|
||||||
|
i = l_numBits.wrapping_sub(2 as libc::c_int as libc::c_uint) as libc::c_int;
|
||||||
|
while i >= 0 as libc::c_int {
|
||||||
|
EccPoint_double_jacobian(rx.as_mut_ptr(), ry.as_mut_ptr(), z.as_mut_ptr());
|
||||||
|
let mut l_index: libc::c_int = (vli_testBit(u1.as_mut_ptr(), i as uint) != 0) as libc::c_int | ((vli_testBit(u2.as_mut_ptr(), i as uint) != 0) as libc::c_int) << 1 as libc::c_int;
|
||||||
|
let mut l_point_0: *mut EccPoint = l_points[l_index as usize];
|
||||||
|
if !l_point_0.is_null() {
|
||||||
|
vli_set(tx.as_mut_ptr(), (*l_point_0).x.as_mut_ptr());
|
||||||
|
vli_set(ty.as_mut_ptr(), (*l_point_0).y.as_mut_ptr());
|
||||||
|
apply_z(tx.as_mut_ptr(), ty.as_mut_ptr(), z.as_mut_ptr());
|
||||||
|
vli_modSub(tz.as_mut_ptr(), rx.as_mut_ptr(), tx.as_mut_ptr(), curve_p.as_mut_ptr());
|
||||||
|
XYcZ_add(tx.as_mut_ptr(), ty.as_mut_ptr(), rx.as_mut_ptr(), ry.as_mut_ptr());
|
||||||
|
vli_modMult_fast(z.as_mut_ptr(), z.as_mut_ptr(), tz.as_mut_ptr());
|
||||||
|
}
|
||||||
|
i -= 1
|
||||||
|
}
|
||||||
|
vli_modInv(z.as_mut_ptr(), z.as_mut_ptr(), curve_p.as_mut_ptr());
|
||||||
|
apply_z(rx.as_mut_ptr(), ry.as_mut_ptr(), z.as_mut_ptr());
|
||||||
|
/* v = x1 (mod n) */
|
||||||
|
if vli_cmp(curve_n.as_mut_ptr(), rx.as_mut_ptr()) != 1 as libc::c_int {
|
||||||
|
vli_sub(rx.as_mut_ptr(), rx.as_mut_ptr(), curve_n.as_mut_ptr());
|
||||||
|
}
|
||||||
|
/* Accept only if v == r. */
|
||||||
|
return (vli_cmp(rx.as_mut_ptr(), l_r.as_mut_ptr()) == 0 as libc::c_int) as libc::c_int;
|
||||||
|
}
|
|
@ -17,12 +17,18 @@ pub fn compute(one_time_key: &[u8], message: &[u8]) -> [u8; POLY1305_MAC_SIZE] {
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::poly1305::*;
|
use crate::poly1305::*;
|
||||||
|
|
||||||
const TV0_INPUT: [u8; 32] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
|
const TV0_INPUT: [u8; 32] = [
|
||||||
const TV0_KEY: [u8; 32] = [0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35];
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
];
|
||||||
|
const TV0_KEY: [u8; 32] = [
|
||||||
|
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35,
|
||||||
|
];
|
||||||
const TV0_TAG: [u8; 16] = [0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07];
|
const TV0_TAG: [u8; 16] = [0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07];
|
||||||
|
|
||||||
const TV1_INPUT: [u8; 12] = [0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21];
|
const TV1_INPUT: [u8; 12] = [0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21];
|
||||||
const TV1_KEY: [u8; 32] = [0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35];
|
const TV1_KEY: [u8; 32] = [
|
||||||
|
0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x33, 0x32, 0x2d, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x50, 0x6f, 0x6c, 0x79, 0x31, 0x33, 0x30, 0x35,
|
||||||
|
];
|
||||||
const TV1_TAG: [u8; 16] = [0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0];
|
const TV1_TAG: [u8; 16] = [0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -5,8 +5,6 @@ use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
|
||||||
use openssl::rand::rand_bytes;
|
use openssl::rand::rand_bytes;
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
|
|
||||||
pub fn next_u32_secure() -> u32 {
|
pub fn next_u32_secure() -> u32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut tmp: [u32; 1] = MaybeUninit::uninit().assume_init();
|
let mut tmp: [u32; 1] = MaybeUninit::uninit().assume_init();
|
||||||
|
@ -110,20 +108,18 @@ impl rand_core_062::RngCore for SecureRandom {
|
||||||
impl rand_core_062::CryptoRng for SecureRandom {}
|
impl rand_core_062::CryptoRng for SecureRandom {}
|
||||||
|
|
||||||
unsafe impl Sync for SecureRandom {}
|
unsafe impl Sync for SecureRandom {}
|
||||||
|
|
||||||
unsafe impl Send for SecureRandom {}
|
unsafe impl Send for SecureRandom {}
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref XORSHIFT64_STATE: AtomicU64 = AtomicU64::new(next_u64_secure());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a non-cryptographic random number.
|
/// Get a non-cryptographic random number.
|
||||||
pub fn xorshift64_random() -> u64 {
|
pub fn xorshift64_random() -> u64 {
|
||||||
let mut x = XORSHIFT64_STATE.load(Ordering::Relaxed);
|
static mut XORSHIFT64_STATE: AtomicU64 = AtomicU64::new(0);
|
||||||
x = x.wrapping_add((x == 0) as u64);
|
let mut x = unsafe { XORSHIFT64_STATE.load(Ordering::Relaxed) };
|
||||||
|
while x == 0 {
|
||||||
|
x = next_u64_secure();
|
||||||
|
}
|
||||||
x ^= x.wrapping_shl(13);
|
x ^= x.wrapping_shl(13);
|
||||||
x ^= x.wrapping_shr(7);
|
x ^= x.wrapping_shr(7);
|
||||||
x ^= x.wrapping_shl(17);
|
x ^= x.wrapping_shl(17);
|
||||||
XORSHIFT64_STATE.store(x, Ordering::Relaxed);
|
unsafe { XORSHIFT64_STATE.store(x, Ordering::Relaxed) };
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,18 +16,18 @@ pub const ED25519_SECRET_KEY_SIZE: usize = 32;
|
||||||
pub const ED25519_SIGNATURE_SIZE: usize = 64;
|
pub const ED25519_SIGNATURE_SIZE: usize = 64;
|
||||||
|
|
||||||
/// Curve25519 key pair for ECDH key agreement.
|
/// Curve25519 key pair for ECDH key agreement.
|
||||||
pub struct C25519KeyPair(x25519_dalek::StaticSecret, Secret<32>, x25519_dalek::PublicKey);
|
pub struct X25519KeyPair(x25519_dalek::StaticSecret, Secret<32>, x25519_dalek::PublicKey);
|
||||||
|
|
||||||
impl C25519KeyPair {
|
impl X25519KeyPair {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn generate() -> C25519KeyPair {
|
pub fn generate() -> X25519KeyPair {
|
||||||
let sk = x25519_dalek::StaticSecret::new(SecureRandom::get());
|
let sk = x25519_dalek::StaticSecret::new(SecureRandom::get());
|
||||||
let sk2 = Secret(sk.to_bytes());
|
let sk2 = Secret(sk.to_bytes());
|
||||||
let pk = x25519_dalek::PublicKey::from(&sk);
|
let pk = x25519_dalek::PublicKey::from(&sk);
|
||||||
C25519KeyPair(sk, sk2, pk)
|
X25519KeyPair(sk, sk2, pk)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_bytes(public_key: &[u8], secret_key: &[u8]) -> Option<C25519KeyPair> {
|
pub fn from_bytes(public_key: &[u8], secret_key: &[u8]) -> Option<X25519KeyPair> {
|
||||||
if public_key.len() == 32 && secret_key.len() == 32 {
|
if public_key.len() == 32 && secret_key.len() == 32 {
|
||||||
/* NOTE: we keep the original secret separately from x25519_dalek's StaticSecret
|
/* NOTE: we keep the original secret separately from x25519_dalek's StaticSecret
|
||||||
* due to how "clamping" is done in the old C++ code vs x25519_dalek. Clamping
|
* due to how "clamping" is done in the old C++ code vs x25519_dalek. Clamping
|
||||||
|
@ -57,7 +57,7 @@ impl C25519KeyPair {
|
||||||
let sk_orig: Secret<32> = Secret(secret_key.try_into().unwrap());
|
let sk_orig: Secret<32> = Secret(secret_key.try_into().unwrap());
|
||||||
let pk = x25519_dalek::PublicKey::from(pk);
|
let pk = x25519_dalek::PublicKey::from(pk);
|
||||||
let sk = x25519_dalek::StaticSecret::from(sk_orig.0.clone());
|
let sk = x25519_dalek::StaticSecret::from(sk_orig.0.clone());
|
||||||
Some(C25519KeyPair(sk, sk_orig, pk))
|
Some(X25519KeyPair(sk, sk_orig, pk))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ impl C25519KeyPair {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for C25519KeyPair {
|
impl Clone for X25519KeyPair {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self(x25519_dalek::StaticSecret::from(self.0.to_bytes()), self.1.clone(), x25519_dalek::PublicKey::from(self.1 .0.clone()))
|
Self(x25519_dalek::StaticSecret::from(self.0.to_bytes()), self.1.clone(), x25519_dalek::PublicKey::from(self.1 .0.clone()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
|
||||||
|
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ impl<O: Send, F: PoolFactory<O>> Pooled<O, F> {
|
||||||
unsafe impl<O: Send, F: PoolFactory<O>> Send for Pooled<O, F> {}
|
unsafe impl<O: Send, F: PoolFactory<O>> Send for Pooled<O, F> {}
|
||||||
unsafe impl<O: Send, F: PoolFactory<O>> Sync for Pooled<O, F> where O: Sync {}
|
unsafe impl<O: Send, F: PoolFactory<O>> Sync for Pooled<O, F> where O: Sync {}
|
||||||
|
|
||||||
impl<O: Send, F: PoolFactory<O>> std::ops::Deref for Pooled<O, F> {
|
impl<O: Send, F: PoolFactory<O>> Deref for Pooled<O, F> {
|
||||||
type Target = O;
|
type Target = O;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -75,6 +76,13 @@ impl<O: Send, F: PoolFactory<O>> std::ops::Deref for Pooled<O, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<O: Send, F: PoolFactory<O>> DerefMut for Pooled<O, F> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { &mut self.0.as_mut().obj }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<O: Send, F: PoolFactory<O>> AsRef<O> for Pooled<O, F> {
|
impl<O: Send, F: PoolFactory<O>> AsRef<O> for Pooled<O, F> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn as_ref(&self) -> &O {
|
fn as_ref(&self) -> &O {
|
||||||
|
@ -82,13 +90,6 @@ impl<O: Send, F: PoolFactory<O>> AsRef<O> for Pooled<O, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<O: Send, F: PoolFactory<O>> std::ops::DerefMut for Pooled<O, F> {
|
|
||||||
#[inline(always)]
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
unsafe { &mut self.0.as_mut().obj }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<O: Send, F: PoolFactory<O>> AsMut<O> for Pooled<O, F> {
|
impl<O: Send, F: PoolFactory<O>> AsMut<O> for Pooled<O, F> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn as_mut(&mut self) -> &mut O {
|
fn as_mut(&mut self) -> &mut O {
|
||||||
|
|
|
@ -39,7 +39,7 @@ pub struct IdentityP384Public {
|
||||||
/// Secret keys associated with an identity.
|
/// Secret keys associated with an identity.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct IdentitySecret {
|
pub struct IdentitySecret {
|
||||||
pub x25519: C25519KeyPair,
|
pub x25519: X25519KeyPair,
|
||||||
pub ed25519: Ed25519KeyPair,
|
pub ed25519: Ed25519KeyPair,
|
||||||
pub p384: Option<IdentityP384Secret>,
|
pub p384: Option<IdentityP384Secret>,
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ impl Identity {
|
||||||
let mut x25519;
|
let mut x25519;
|
||||||
let mut x25519_pub;
|
let mut x25519_pub;
|
||||||
loop {
|
loop {
|
||||||
x25519 = C25519KeyPair::generate();
|
x25519 = X25519KeyPair::generate();
|
||||||
x25519_pub = x25519.public_bytes();
|
x25519_pub = x25519.public_bytes();
|
||||||
|
|
||||||
sha.update(&x25519_pub);
|
sha.update(&x25519_pub);
|
||||||
|
@ -475,7 +475,7 @@ impl Identity {
|
||||||
ed25519: b.ed25519,
|
ed25519: b.ed25519,
|
||||||
p384: None,
|
p384: None,
|
||||||
secret: Some(IdentitySecret {
|
secret: Some(IdentitySecret {
|
||||||
x25519: C25519KeyPair::from_bytes(&b.x25519, &b.x25519_secret)?,
|
x25519: X25519KeyPair::from_bytes(&b.x25519, &b.x25519_secret)?,
|
||||||
ed25519: Ed25519KeyPair::from_bytes(&b.ed25519, &b.ed25519_secret)?,
|
ed25519: Ed25519KeyPair::from_bytes(&b.ed25519, &b.ed25519_secret)?,
|
||||||
p384: None,
|
p384: None,
|
||||||
}),
|
}),
|
||||||
|
@ -493,12 +493,7 @@ impl Identity {
|
||||||
}
|
}
|
||||||
IdentityBytes::X25519P384Public(b) => {
|
IdentityBytes::X25519P384Public(b) => {
|
||||||
let b: &packed::V1 = bytes_as_flat_object(b);
|
let b: &packed::V1 = bytes_as_flat_object(b);
|
||||||
if b.v0.key_type == 0
|
if b.v0.key_type == 0 && b.v0.secret_length == 0 && b.v0.reserved == 0x03 && u16::from_be_bytes(b.v0.ext_len) == (Self::BYTE_LENGTH_X25519P384_PUBLIC - Self::BYTE_LENGTH_X25519_PUBLIC) as u16 && b.key_type_flags == Self::ALGORITHM_EC_NIST_P384 {
|
||||||
&& b.v0.secret_length == 0
|
|
||||||
&& b.v0.reserved == 0x03
|
|
||||||
&& u16::from_be_bytes(b.v0.ext_len) == (Self::BYTE_LENGTH_X25519P384_PUBLIC - Self::BYTE_LENGTH_X25519_PUBLIC) as u16
|
|
||||||
&& b.key_type_flags == Self::ALGORITHM_EC_NIST_P384
|
|
||||||
{
|
|
||||||
Some(Self {
|
Some(Self {
|
||||||
address: Address::from_bytes_fixed(&b.v0.address)?,
|
address: Address::from_bytes_fixed(&b.v0.address)?,
|
||||||
x25519: b.v0.x25519,
|
x25519: b.v0.x25519,
|
||||||
|
@ -544,7 +539,7 @@ impl Identity {
|
||||||
ed25519_self_signature: b.ed25519_self_signature,
|
ed25519_self_signature: b.ed25519_self_signature,
|
||||||
}),
|
}),
|
||||||
secret: Some(IdentitySecret {
|
secret: Some(IdentitySecret {
|
||||||
x25519: C25519KeyPair::from_bytes(&b.v0s.x25519, &b.v0s.x25519_secret)?,
|
x25519: X25519KeyPair::from_bytes(&b.v0s.x25519, &b.v0s.x25519_secret)?,
|
||||||
ed25519: Ed25519KeyPair::from_bytes(&b.v0s.ed25519, &b.v0s.ed25519_secret)?,
|
ed25519: Ed25519KeyPair::from_bytes(&b.v0s.ed25519, &b.v0s.ed25519_secret)?,
|
||||||
p384: Some(IdentityP384Secret {
|
p384: Some(IdentityP384Secret {
|
||||||
ecdh: P384KeyPair::from_bytes(&b.ecdh, &b.ecdh_secret)?,
|
ecdh: P384KeyPair::from_bytes(&b.ecdh, &b.ecdh_secret)?,
|
||||||
|
@ -740,7 +735,7 @@ impl FromStr for Identity {
|
||||||
}
|
}
|
||||||
Some(IdentitySecret {
|
Some(IdentitySecret {
|
||||||
x25519: {
|
x25519: {
|
||||||
let tmp = C25519KeyPair::from_bytes(&keys[0].as_slice()[0..32], &keys[1].as_slice()[0..32]);
|
let tmp = X25519KeyPair::from_bytes(&keys[0].as_slice()[0..32], &keys[1].as_slice()[0..32]);
|
||||||
if tmp.is_none() {
|
if tmp.is_none() {
|
||||||
return Err(InvalidFormatError);
|
return Err(InvalidFormatError);
|
||||||
}
|
}
|
||||||
|
@ -977,7 +972,10 @@ mod tests {
|
||||||
let self_agree_expected = hex::from_string("de904fc90ff3a2b96b739b926e623113f5334c80841b654509b77916c4c4a6eb0ca69ec6ed01a7f04aee17c546b30ba4");
|
let self_agree_expected = hex::from_string("de904fc90ff3a2b96b739b926e623113f5334c80841b654509b77916c4c4a6eb0ca69ec6ed01a7f04aee17c546b30ba4");
|
||||||
|
|
||||||
// Test self-agree with a known good x25519-only (v0) identity.
|
// Test self-agree with a known good x25519-only (v0) identity.
|
||||||
let id = Identity::from_str("728efdb79d:0:3077ed0084d8d48a3ac628af6b45d9351e823bff34bc4376cddfc77a3d73a966c7d347bdcc1244d0e99e1b9c961ff5e963092e90ca43b47ff58c114d2d699664:2afaefcd1dca336ed59957eb61919b55009850b0b7088af3ee142672b637d1d49cc882b30a006f9eee42f2211ef8fe1cbe99a16a4436737fc158ce2243c15f12").unwrap();
|
let id = Identity::from_str(
|
||||||
|
"728efdb79d:0:3077ed0084d8d48a3ac628af6b45d9351e823bff34bc4376cddfc77a3d73a966c7d347bdcc1244d0e99e1b9c961ff5e963092e90ca43b47ff58c114d2d699664:2afaefcd1dca336ed59957eb61919b55009850b0b7088af3ee142672b637d1d49cc882b30a006f9eee42f2211ef8fe1cbe99a16a4436737fc158ce2243c15f12",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
assert!(id.validate_identity());
|
assert!(id.validate_identity());
|
||||||
let self_agree = id.agree(&id).unwrap();
|
let self_agree = id.agree(&id).unwrap();
|
||||||
assert!(self_agree_expected.as_slice().eq(&self_agree.as_bytes()[..48]));
|
assert!(self_agree_expected.as_slice().eq(&self_agree.as_bytes()[..48]));
|
||||||
|
|
10
rustfmt.toml
10
rustfmt.toml
|
@ -1,12 +1,12 @@
|
||||||
#unstable_features = true
|
#unstable_features = true
|
||||||
max_width = 256
|
max_width = 300
|
||||||
#use_small_heuristics = "Max"
|
#use_small_heuristics = "Max"
|
||||||
use_small_heuristics = "Default"
|
|
||||||
tab_spaces = 4
|
|
||||||
newline_style = "Unix"
|
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
struct_lit_width = 60
|
|
||||||
empty_item_single_line = true
|
empty_item_single_line = true
|
||||||
|
newline_style = "Unix"
|
||||||
|
struct_lit_width = 60
|
||||||
|
tab_spaces = 4
|
||||||
|
use_small_heuristics = "Default"
|
||||||
#fn_single_line = true
|
#fn_single_line = true
|
||||||
#hex_literal_case = "Lower"
|
#hex_literal_case = "Lower"
|
||||||
#merge_imports = true
|
#merge_imports = true
|
||||||
|
|
Loading…
Add table
Reference in a new issue