2016-08-28 21:04:46 -07:00
|
|
|
use std::ops::{Add,Sub,Neg,Mul};
|
|
|
|
use fields::{FieldElement, Fq, Fq2, Fr, const_fp};
|
|
|
|
use arith::U256;
|
|
|
|
use std::fmt;
|
|
|
|
use rand::Rng;
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
|
|
|
|
2016-08-28 21:04:46 -07:00
|
|
|
pub trait GroupElement: Sized +
|
|
|
|
Copy +
|
|
|
|
Clone +
|
|
|
|
PartialEq +
|
|
|
|
Eq +
|
|
|
|
fmt::Debug +
|
|
|
|
Add<Output=Self> +
|
|
|
|
Sub<Output=Self> +
|
|
|
|
Neg<Output=Self> +
|
|
|
|
Mul<Fr, Output=Self>
|
|
|
|
{
|
|
|
|
fn zero() -> Self;
|
|
|
|
fn one() -> Self;
|
|
|
|
fn random<R: Rng>(rng: &mut R) -> Self;
|
|
|
|
fn is_zero(&self) -> bool;
|
|
|
|
fn double(&self) -> Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait GroupParams: Sized {
|
2016-09-09 00:12:25 -07:00
|
|
|
type Base: FieldElement + Decodable + Encodable;
|
2016-08-28 21:04:46 -07:00
|
|
|
|
|
|
|
fn name() -> &'static str;
|
2016-09-09 00:12:25 -07:00
|
|
|
fn one() -> G<Self>;
|
|
|
|
fn coeff_b() -> Self::Base;
|
2016-08-28 21:04:46 -07:00
|
|
|
}
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
pub struct G<P: GroupParams> {
|
2016-08-28 21:04:46 -07:00
|
|
|
x: P::Base,
|
|
|
|
y: P::Base,
|
|
|
|
z: P::Base
|
|
|
|
}
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
pub struct AffineG<P: GroupParams> {
|
|
|
|
x: P::Base,
|
2016-09-09 10:31:46 -07:00
|
|
|
y: P::Base,
|
|
|
|
infinity: bool
|
2016-09-09 00:12:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<P: GroupParams> fmt::Debug for G<P> {
|
2016-08-28 21:04:46 -07:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "{}({:?}, {:?}, {:?})", P::name(), self.x, self.y, self.z)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
impl<P: GroupParams> Clone for G<P> {
|
2016-08-28 21:04:46 -07:00
|
|
|
fn clone(&self) -> Self {
|
2016-09-09 00:12:25 -07:00
|
|
|
G {
|
2016-08-28 21:04:46 -07:00
|
|
|
x: self.x,
|
|
|
|
y: self.y,
|
|
|
|
z: self.z
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-09-09 00:12:25 -07:00
|
|
|
impl<P: GroupParams> Copy for G<P> {}
|
2016-08-28 21:04:46 -07:00
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
impl<P: GroupParams> PartialEq for G<P> {
|
2016-08-28 21:04:46 -07:00
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
if self.is_zero() {
|
|
|
|
return other.is_zero()
|
|
|
|
}
|
|
|
|
|
|
|
|
if other.is_zero() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let z1_squared = self.z.squared();
|
|
|
|
let z2_squared = other.z.squared();
|
|
|
|
|
|
|
|
if self.x * z2_squared != other.x * z1_squared {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let z1_cubed = self.z * z1_squared;
|
|
|
|
let z2_cubed = other.z * z2_squared;
|
|
|
|
|
|
|
|
if self.y * z2_cubed != other.y * z1_cubed {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2016-09-09 00:12:25 -07:00
|
|
|
impl<P: GroupParams> Eq for G<P> { }
|
|
|
|
|
|
|
|
impl<P: GroupParams> G<P> {
|
2016-09-09 10:31:46 -07:00
|
|
|
fn to_affine(&self) -> AffineG<P> {
|
2016-09-09 00:12:25 -07:00
|
|
|
if self.z.is_zero() {
|
2016-09-09 10:31:46 -07:00
|
|
|
AffineG {
|
|
|
|
x: P::Base::zero(),
|
|
|
|
y: P::Base::one(),
|
|
|
|
infinity: true
|
|
|
|
}
|
2016-09-09 00:12:25 -07:00
|
|
|
} else {
|
|
|
|
let zinv = self.z.inverse().unwrap();
|
|
|
|
let zinv_squared = zinv.squared();
|
|
|
|
|
2016-09-09 10:31:46 -07:00
|
|
|
AffineG {
|
2016-09-09 00:12:25 -07:00
|
|
|
x: self.x * zinv_squared,
|
2016-09-09 10:31:46 -07:00
|
|
|
y: self.y * (zinv_squared * zinv),
|
|
|
|
infinity: false
|
|
|
|
}
|
2016-09-09 00:12:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<P: GroupParams> AffineG<P> {
|
2016-09-09 10:31:46 -07:00
|
|
|
fn zero() -> Self {
|
|
|
|
AffineG {
|
|
|
|
x: P::Base::zero(),
|
|
|
|
y: P::Base::one(),
|
|
|
|
infinity: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
fn to_jacobian(&self) -> G<P> {
|
|
|
|
G {
|
|
|
|
x: self.x,
|
|
|
|
y: self.y,
|
2016-09-09 10:31:46 -07:00
|
|
|
z: if self.infinity {
|
|
|
|
P::Base::zero()
|
|
|
|
} else {
|
|
|
|
P::Base::one()
|
|
|
|
}
|
2016-09-09 00:12:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<P: GroupParams> Encodable for G<P> {
|
|
|
|
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
2016-09-09 10:31:46 -07:00
|
|
|
self.to_affine().encode(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<P: GroupParams> Encodable for AffineG<P> {
|
|
|
|
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
|
|
|
if self.infinity {
|
|
|
|
let l: u8 = 0;
|
|
|
|
try!(l.encode(s));
|
|
|
|
} else {
|
|
|
|
let l: u8 = 4;
|
|
|
|
try!(l.encode(s));
|
|
|
|
try!(self.x.encode(s));
|
|
|
|
try!(self.y.encode(s));
|
2016-09-09 00:12:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2016-08-28 21:04:46 -07:00
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
impl<P: GroupParams> Decodable for G<P> {
|
|
|
|
fn decode<S: Decoder>(s: &mut S) -> Result<G<P>, S::Error> {
|
2016-09-09 10:31:46 -07:00
|
|
|
Ok(try!(AffineG::decode(s)).to_jacobian())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<P: GroupParams> Decodable for AffineG<P> {
|
|
|
|
fn decode<S: Decoder>(s: &mut S) -> Result<AffineG<P>, S::Error> {
|
2016-09-09 00:12:25 -07:00
|
|
|
let l = try!(u8::decode(s));
|
|
|
|
if l == 0 {
|
2016-09-09 10:31:46 -07:00
|
|
|
Ok(AffineG::zero())
|
2016-09-09 00:12:25 -07:00
|
|
|
} else if l == 4 {
|
|
|
|
let x = try!(P::Base::decode(s));
|
|
|
|
let y = try!(P::Base::decode(s));
|
|
|
|
|
|
|
|
// y^2 = x^3 + b
|
|
|
|
if y.squared() == (x.squared() * x) + P::coeff_b() {
|
2016-09-09 10:31:46 -07:00
|
|
|
Ok(AffineG {
|
2016-09-09 00:12:25 -07:00
|
|
|
x: x,
|
|
|
|
y: y,
|
2016-09-09 10:31:46 -07:00
|
|
|
infinity: false
|
2016-09-09 00:12:25 -07:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
Err(s.error("point is not on the curve"))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Err(s.error("invalid leading byte for uncompressed group element"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<P: GroupParams> GroupElement for G<P> {
|
2016-08-28 21:04:46 -07:00
|
|
|
fn zero() -> Self {
|
2016-09-09 00:12:25 -07:00
|
|
|
G {
|
2016-08-28 21:04:46 -07:00
|
|
|
x: P::Base::zero(),
|
|
|
|
y: P::Base::one(),
|
|
|
|
z: P::Base::zero()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn one() -> Self {
|
|
|
|
P::one()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn random<R: Rng>(rng: &mut R) -> Self {
|
|
|
|
P::one() * Fr::random(rng)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_zero(&self) -> bool {
|
|
|
|
self.z.is_zero()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn double(&self) -> Self {
|
|
|
|
let a = self.x.squared();
|
|
|
|
let b = self.y.squared();
|
|
|
|
let c = b.squared();
|
|
|
|
let mut d = (self.x + b).squared() - a - c;
|
|
|
|
d = d + d;
|
|
|
|
let e = a + a + a;
|
|
|
|
let f = e.squared();
|
|
|
|
let x3 = f - (d + d);
|
|
|
|
let mut eight_c = c + c;
|
|
|
|
eight_c = eight_c + eight_c;
|
|
|
|
eight_c = eight_c + eight_c;
|
|
|
|
let y1z1 = self.y * self.z;
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
G {
|
2016-08-28 21:04:46 -07:00
|
|
|
x: x3,
|
|
|
|
y: e * (d - x3) - eight_c,
|
|
|
|
z: y1z1 + y1z1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
impl<P: GroupParams> Mul<Fr> for G<P> {
|
|
|
|
type Output = G<P>;
|
2016-08-28 21:04:46 -07:00
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
fn mul(self, other: Fr) -> G<P> {
|
|
|
|
let mut res = G::zero();
|
2016-08-28 21:04:46 -07:00
|
|
|
let mut found_one = false;
|
|
|
|
|
|
|
|
for i in U256::from(other).bits() {
|
|
|
|
if found_one {
|
|
|
|
res = res.double();
|
|
|
|
}
|
|
|
|
|
|
|
|
if i {
|
|
|
|
found_one = true;
|
|
|
|
res = res + self;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
res
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
impl<P: GroupParams> Add<G<P>> for G<P> {
|
|
|
|
type Output = G<P>;
|
2016-08-28 21:04:46 -07:00
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
fn add(self, other: G<P>) -> G<P> {
|
2016-08-28 21:04:46 -07:00
|
|
|
if self.is_zero() {
|
|
|
|
return other;
|
|
|
|
}
|
|
|
|
|
|
|
|
if other.is_zero() {
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
let z1_squared = self.z.squared();
|
|
|
|
let z2_squared = other.z.squared();
|
|
|
|
let u1 = self.x * z2_squared;
|
|
|
|
let u2 = other.x * z1_squared;
|
|
|
|
let z1_cubed = self.z * z1_squared;
|
|
|
|
let z2_cubed = other.z * z2_squared;
|
|
|
|
let s1 = self.y * z2_cubed;
|
|
|
|
let s2 = other.y * z1_cubed;
|
|
|
|
|
|
|
|
if u1 == u2 && s1 == s2 {
|
|
|
|
self.double()
|
|
|
|
} else {
|
|
|
|
let h = u2 - u1;
|
|
|
|
let s2_minus_s1 = s2 - s1;
|
|
|
|
let i = (h + h).squared();
|
|
|
|
let j = h * i;
|
|
|
|
let r = s2_minus_s1 + s2_minus_s1;
|
|
|
|
let v = u1 * i;
|
|
|
|
let s1_j = s1 * j;
|
|
|
|
let x3 = r.squared() - j - (v + v);
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
G {
|
2016-08-28 21:04:46 -07:00
|
|
|
x: x3,
|
|
|
|
y: r * (v - x3) - (s1_j + s1_j),
|
|
|
|
z: ((self.z + other.z).squared() - z1_squared - z2_squared) * h
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
impl<P: GroupParams> Neg for G<P> {
|
|
|
|
type Output = G<P>;
|
2016-08-28 21:04:46 -07:00
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
fn neg(self) -> G<P> {
|
|
|
|
G {
|
2016-08-28 21:04:46 -07:00
|
|
|
x: self.x,
|
|
|
|
y: -self.y,
|
|
|
|
z: self.z
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
impl<P: GroupParams> Sub<G<P>> for G<P> {
|
|
|
|
type Output = G<P>;
|
2016-08-28 21:04:46 -07:00
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
fn sub(self, other: G<P>) -> G<P> {
|
2016-08-28 21:04:46 -07:00
|
|
|
self + (-other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct G1Params;
|
|
|
|
|
|
|
|
impl GroupParams for G1Params {
|
|
|
|
type Base = Fq;
|
|
|
|
|
|
|
|
fn name() -> &'static str { "G1" }
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
fn one() -> G<Self> {
|
|
|
|
G {
|
2016-08-28 21:04:46 -07:00
|
|
|
x: Fq::one(),
|
|
|
|
y: const_fp([0xa6ba871b8b1e1b3a, 0x14f1d651eb8e167b, 0xccdd46def0f28c58, 0x1c14ef83340fbe5e]),
|
|
|
|
z: Fq::one()
|
|
|
|
}
|
|
|
|
}
|
2016-09-09 00:12:25 -07:00
|
|
|
|
|
|
|
fn coeff_b() -> Fq {
|
|
|
|
const_fp([0x7a17caa950ad28d7, 0x1f6ac17ae15521b9, 0x334bea4e696bd284, 0x2a1f6744ce179d8e])
|
|
|
|
}
|
2016-08-28 21:04:46 -07:00
|
|
|
}
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
pub type G1 = G<G1Params>;
|
2016-08-28 21:04:46 -07:00
|
|
|
|
|
|
|
pub struct G2Params;
|
|
|
|
|
|
|
|
impl GroupParams for G2Params {
|
|
|
|
type Base = Fq2;
|
|
|
|
|
|
|
|
fn name() -> &'static str { "G2" }
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
fn one() -> G<Self> {
|
|
|
|
G {
|
|
|
|
x: Fq2::new(
|
|
|
|
const_fp([0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b]),
|
|
|
|
const_fp([0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b])
|
|
|
|
),
|
|
|
|
y: Fq2::new(
|
|
|
|
const_fp([0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206]),
|
|
|
|
const_fp([0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482])
|
|
|
|
),
|
2016-08-28 21:04:46 -07:00
|
|
|
z: Fq2::one()
|
|
|
|
}
|
|
|
|
}
|
2016-09-09 00:12:25 -07:00
|
|
|
|
|
|
|
fn coeff_b() -> Fq2 {
|
|
|
|
Fq2::new(
|
|
|
|
const_fp([0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d]),
|
|
|
|
const_fp([0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d])
|
|
|
|
)
|
|
|
|
}
|
2016-08-28 21:04:46 -07:00
|
|
|
}
|
|
|
|
|
2016-09-09 00:12:25 -07:00
|
|
|
pub type G2 = G<G2Params>;
|
2016-08-28 21:04:46 -07:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_g1() {
|
|
|
|
tests::group_trials::<G1>();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_g2() {
|
|
|
|
tests::group_trials::<G2>();
|
|
|
|
}
|
2016-09-09 00:12:25 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_affine_jacobian_conversion() {
|
|
|
|
let rng = &mut ::rand::thread_rng();
|
|
|
|
|
2016-09-09 10:31:46 -07:00
|
|
|
assert!(G1::zero().to_affine().infinity);
|
|
|
|
assert!(G2::zero().to_affine().infinity);
|
2016-09-09 00:12:25 -07:00
|
|
|
|
|
|
|
for _ in 0..1000 {
|
|
|
|
let a = G1::one() * Fr::random(rng);
|
2016-09-09 10:31:46 -07:00
|
|
|
let b = a.to_affine();
|
2016-09-09 00:12:25 -07:00
|
|
|
let c = b.to_jacobian();
|
|
|
|
|
|
|
|
assert_eq!(a, c);
|
|
|
|
}
|
|
|
|
|
|
|
|
for _ in 0..1000 {
|
|
|
|
let a = G2::one() * Fr::random(rng);
|
2016-09-09 10:31:46 -07:00
|
|
|
let b = a.to_affine();
|
2016-09-09 00:12:25 -07:00
|
|
|
let c = b.to_jacobian();
|
|
|
|
|
|
|
|
assert_eq!(a, c);
|
|
|
|
}
|
|
|
|
}
|