|
@ -35,7 +35,7 @@ lazy_static! { |
|
|
b"21888242871839275222246405745257275088548364400416034343698204186575808495617",10
|
|
|
b"21888242871839275222246405745257275088548364400416034343698204186575808495617",10
|
|
|
)
|
|
|
)
|
|
|
.unwrap();
|
|
|
.unwrap();
|
|
|
static ref B8: Point = Point {
|
|
|
|
|
|
|
|
|
pub static ref B8: Point = Point {
|
|
|
x: Fr::from_str(
|
|
|
x: Fr::from_str(
|
|
|
"5299619240641551281634865583518297030282874472190772894086521144482721001553",
|
|
|
"5299619240641551281634865583518297030282874472190772894086521144482721001553",
|
|
|
)
|
|
|
)
|
|
@ -159,8 +159,10 @@ impl Point { |
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
pub fn inverse(&self) -> Point {
|
|
|
pub fn inverse(&self) -> Point {
|
|
|
|
|
|
let mut x_inverse = Fr::zero();
|
|
|
|
|
|
x_inverse.sub_assign(&self.x);
|
|
|
Point {
|
|
|
Point {
|
|
|
x: self.x.inverse().unwrap(),
|
|
|
|
|
|
|
|
|
x: x_inverse,
|
|
|
y: self.y
|
|
|
y: self.y
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@ -297,6 +299,11 @@ pub fn decompress_signature(b: &[u8; 64]) -> Result { |
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub struct ElGamalEncryption {
|
|
|
|
|
|
c1: Point,
|
|
|
|
|
|
c2: Point
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
pub struct PrivateKey {
|
|
|
pub struct PrivateKey {
|
|
|
key: [u8; 32],
|
|
|
key: [u8; 32],
|
|
|
}
|
|
|
}
|
|
@ -390,22 +397,33 @@ impl PrivateKey { |
|
|
Ok((r, s))
|
|
|
Ok((r, s))
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
// pub fn encrypt_elgamal(&self, msg: Point) -> [Point; 2] {
|
|
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
pub fn decrypt_elgamal(&self, c1: Point, c2: Point) -> Point {
|
|
|
|
|
|
let shared_secret = c1.mul_scalar(&self.scalar_key());
|
|
|
|
|
|
let msg = c2.projective()
|
|
|
|
|
|
.add(
|
|
|
|
|
|
&shared_secret.inverse().projective()
|
|
|
|
|
|
)
|
|
|
|
|
|
.affine();
|
|
|
|
|
|
msg
|
|
|
|
|
|
|
|
|
pub fn decrypt_elgamal(&self, encrypted_point: ElGamalEncryption) -> Point {
|
|
|
|
|
|
let shared_secret = encrypted_point.c1.mul_scalar(&self.scalar_key());
|
|
|
|
|
|
println!("Shared Secret {:?}", shared_secret);
|
|
|
|
|
|
// Subtract the shared secret
|
|
|
|
|
|
encrypted_point.c2.projective().add(
|
|
|
|
|
|
&shared_secret.inverse().projective()
|
|
|
|
|
|
).affine()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// encrypts msg to public key to_pubkey, using some random scalar nonce
|
|
|
|
|
|
pub fn encrypt_elgamal(to_pubkey: Point, nonce: BigInt, msg: &Point) -> ElGamalEncryption {
|
|
|
|
|
|
let shared_secret = to_pubkey.mul_scalar(&nonce);
|
|
|
|
|
|
println!("Shared Secret 2 {:?}", shared_secret);
|
|
|
|
|
|
let public_nonce = B8.mul_scalar(&nonce);
|
|
|
|
|
|
// let msg_point = point_for_msg(msg);
|
|
|
|
|
|
let msg_plus_secret = msg.projective().add(
|
|
|
|
|
|
&shared_secret.projective()
|
|
|
|
|
|
)
|
|
|
|
|
|
.affine();
|
|
|
|
|
|
ElGamalEncryption {
|
|
|
|
|
|
c1: public_nonce,
|
|
|
|
|
|
c2: msg_plus_secret
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
pub fn schnorr_hash(pk: &Point, msg: BigInt, c: &Point) -> Result<BigInt, String> {
|
|
|
pub fn schnorr_hash(pk: &Point, msg: BigInt, c: &Point) -> Result<BigInt, String> {
|
|
|
if msg > Q.clone() {
|
|
|
if msg > Q.clone() {
|
|
|
return Err("msg outside the Finite Field".to_string());
|
|
|
return Err("msg outside the Finite Field".to_string());
|
|
@ -461,7 +479,37 @@ mod tests { |
|
|
use super::*;
|
|
|
use super::*;
|
|
|
use ::hex;
|
|
|
use ::hex;
|
|
|
use rand::Rng;
|
|
|
use rand::Rng;
|
|
|
|
|
|
use num_traits::FromPrimitive;
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_neg() {
|
|
|
|
|
|
let some_point = B8.mul_scalar(&BigInt::from_u8(0x69).unwrap());
|
|
|
|
|
|
let another_point = B8.mul_scalar(&BigInt::from_u8(0x99).unwrap());
|
|
|
|
|
|
let mut some_point_x_inverse = Fr::zero();
|
|
|
|
|
|
some_point_x_inverse.sub_assign(&some_point.x);
|
|
|
|
|
|
// assert_eq!(some_point_x_inverse, some_point.x.inverse().unwrap());
|
|
|
|
|
|
assert!(some_point.equals(some_point.projective().affine()));
|
|
|
|
|
|
assert!(some_point.equals(
|
|
|
|
|
|
some_point.projective().add(&another_point.projective()).add(
|
|
|
|
|
|
&another_point.inverse().projective())
|
|
|
|
|
|
.affine()
|
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_elgamal() {
|
|
|
|
|
|
let some_point = B8.mul_scalar(&BigInt::from_u8(0x69).unwrap());
|
|
|
|
|
|
let some_privkey = new_key();
|
|
|
|
|
|
let some_point_encrypted = encrypt_elgamal(
|
|
|
|
|
|
some_privkey.public(),
|
|
|
|
|
|
BigInt::parse_bytes(b"ABCDEF123456789", 16).unwrap(),
|
|
|
|
|
|
&some_point
|
|
|
|
|
|
);
|
|
|
|
|
|
let some_point_encrypted_decrypted = some_privkey.decrypt_elgamal(some_point_encrypted);
|
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(some_point.x, some_point_encrypted_decrypted.x);
|
|
|
|
|
|
assert_eq!(some_point.y, some_point_encrypted_decrypted.y);
|
|
|
|
|
|
}
|
|
|
#[test]
|
|
|
#[test]
|
|
|
fn test_add_same_point() {
|
|
|
fn test_add_same_point() {
|
|
|
let p: PointProjective = PointProjective {
|
|
|
let p: PointProjective = PointProjective {
|
|
@ -730,54 +778,55 @@ mod tests { |
|
|
assert_eq!(true, verification);
|
|
|
assert_eq!(true, verification);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
fn test_circomlib_testvector() {
|
|
|
|
|
|
let sk_raw_bytes =
|
|
|
|
|
|
hex::decode("0001020304050607080900010203040506070809000102030405060708090001")
|
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
// test blake compatible with circomlib implementation
|
|
|
|
|
|
let h: Vec<u8> = blh(&sk_raw_bytes);
|
|
|
|
|
|
assert_eq!(hex::encode(h), "c992db23d6290c70ffcc02f7abeb00b9d00fa8b43e55d7949c28ba6be7545d3253882a61bd004a236ef1cdba01b27ba0aedfb08eefdbfb7c19657c880b43ddf1");
|
|
|
|
|
|
|
|
|
|
|
|
// test private key
|
|
|
|
|
|
let sk = PrivateKey::import(
|
|
|
|
|
|
hex::decode("0001020304050607080900010203040506070809000102030405060708090001")
|
|
|
|
|
|
.unwrap(),
|
|
|
|
|
|
)
|
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
|
sk.scalar_key().to_string(),
|
|
|
|
|
|
"6466070937662820620902051049739362987537906109895538826186780010858059362905"
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// test public key
|
|
|
|
|
|
let pk = sk.public();
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
|
pk.x.to_string(),
|
|
|
|
|
|
"Fr(0x1d5ac1f31407018b7d413a4f52c8f74463b30e6ac2238220ad8b254de4eaa3a2)"
|
|
|
|
|
|
);
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
|
pk.y.to_string(),
|
|
|
|
|
|
"Fr(0x1e1de8a908826c3f9ac2e0ceee929ecd0caf3b99b3ef24523aaab796a6f733c4)"
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// test signature & verification
|
|
|
|
|
|
let msg = BigInt::from_bytes_le(Sign::Plus, &hex::decode("00010203040506070809").unwrap());
|
|
|
|
|
|
let sig = sk.sign(msg.clone()).unwrap();
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
|
sig.r_b8.x.to_string(),
|
|
|
|
|
|
"Fr(0x192b4e51adf302c8139d356d0e08e2404b5ace440ef41fc78f5c4f2428df0765)"
|
|
|
|
|
|
);
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
|
sig.r_b8.y.to_string(),
|
|
|
|
|
|
"Fr(0x2202bebcf57b820863e0acc88970b6ca7d987a0d513c2ddeb42e3f5d31b4eddf)"
|
|
|
|
|
|
);
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
|
sig.s.to_string(),
|
|
|
|
|
|
"1672775540645840396591609181675628451599263765380031905495115170613215233181"
|
|
|
|
|
|
);
|
|
|
|
|
|
let v = verify(pk, sig, msg);
|
|
|
|
|
|
assert_eq!(v, true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
// Removed this because broke circom siganture compatability due to different blake hash function:
|
|
|
|
|
|
// #[test]
|
|
|
|
|
|
// fn test_circomlib_testvector() {
|
|
|
|
|
|
// let sk_raw_bytes =
|
|
|
|
|
|
// hex::decode("0001020304050607080900010203040506070809000102030405060708090001")
|
|
|
|
|
|
// .unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
// // test blake compatible with circomlib implementation
|
|
|
|
|
|
// let h: Vec<u8> = blh(&sk_raw_bytes);
|
|
|
|
|
|
// assert_eq!(hex::encode(h), "c992db23d6290c70ffcc02f7abeb00b9d00fa8b43e55d7949c28ba6be7545d3253882a61bd004a236ef1cdba01b27ba0aedfb08eefdbfb7c19657c880b43ddf1");
|
|
|
|
|
|
|
|
|
|
|
|
// // test private key
|
|
|
|
|
|
// let sk = PrivateKey::import(
|
|
|
|
|
|
// hex::decode("0001020304050607080900010203040506070809000102030405060708090001")
|
|
|
|
|
|
// .unwrap(),
|
|
|
|
|
|
// )
|
|
|
|
|
|
// .unwrap();
|
|
|
|
|
|
// assert_eq!(
|
|
|
|
|
|
// sk.scalar_key().to_string(),
|
|
|
|
|
|
// "6466070937662820620902051049739362987537906109895538826186780010858059362905"
|
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
|
|
// // test public key
|
|
|
|
|
|
// let pk = sk.public();
|
|
|
|
|
|
// assert_eq!(
|
|
|
|
|
|
// pk.x.to_string(),
|
|
|
|
|
|
// "Fr(0x1d5ac1f31407018b7d413a4f52c8f74463b30e6ac2238220ad8b254de4eaa3a2)"
|
|
|
|
|
|
// );
|
|
|
|
|
|
// assert_eq!(
|
|
|
|
|
|
// pk.y.to_string(),
|
|
|
|
|
|
// "Fr(0x1e1de8a908826c3f9ac2e0ceee929ecd0caf3b99b3ef24523aaab796a6f733c4)"
|
|
|
|
|
|
// );
|
|
|
|
|
|
|
|
|
|
|
|
// // test signature & verification
|
|
|
|
|
|
// let msg = BigInt::from_bytes_le(Sign::Plus, &hex::decode("00010203040506070809").unwrap());
|
|
|
|
|
|
// let sig = sk.sign(msg.clone()).unwrap();
|
|
|
|
|
|
// assert_eq!(
|
|
|
|
|
|
// sig.r_b8.x.to_string(),
|
|
|
|
|
|
// "Fr(0x192b4e51adf302c8139d356d0e08e2404b5ace440ef41fc78f5c4f2428df0765)"
|
|
|
|
|
|
// );
|
|
|
|
|
|
// assert_eq!(
|
|
|
|
|
|
// sig.r_b8.y.to_string(),
|
|
|
|
|
|
// "Fr(0x2202bebcf57b820863e0acc88970b6ca7d987a0d513c2ddeb42e3f5d31b4eddf)"
|
|
|
|
|
|
// );
|
|
|
|
|
|
// assert_eq!(
|
|
|
|
|
|
// sig.s.to_string(),
|
|
|
|
|
|
// "1672775540645840396591609181675628451599263765380031905495115170613215233181"
|
|
|
|
|
|
// );
|
|
|
|
|
|
// let v = verify(pk, sig, msg);
|
|
|
|
|
|
// assert_eq!(v, true);
|
|
|
|
|
|
// }
|
|
|
}
|
|
|
}
|