babyjubjub-rs/src/lib.rs
src/lib.rsRaw
1extern crate num;
2extern crate num_bigint;
3extern crate num_traits;
4
5use num_bigint::BigInt;
6use num_traits::{One, Zero};
7
8mod utils;
9
10#[derive(Clone, Debug)]
11pub struct Point {
12 pub x: BigInt,
13 pub y: BigInt,
14}
15
16pub struct Babyjubjub {
17 d: BigInt,
18 a: BigInt,
19 q: BigInt,
20}
21
22impl Babyjubjub {
23 pub fn new() -> Babyjubjub {
24 let d: BigInt = BigInt::parse_bytes(b"168696", 10).unwrap();
25 let a: BigInt = BigInt::parse_bytes(b"168700", 10).unwrap();
26 let q: BigInt = BigInt::parse_bytes(
27 b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
28 10,
29 )
30 .unwrap();
31 Babyjubjub { d: d, a: a, q: q }
32 }
33
34 pub fn add(&self, p: &Point, q: &Point) -> Point {
35 // x = (x1*y2+y1*x2)/(c*(1+d*x1*x2*y1*y2))
36 // y = (y1*y2-x1*x2)/(c*(1-d*x1*x2*y1*y2))
37
38 // x = (x1 * y2 + y1 * x2) / (1 + d * x1 * y1 * y2)
39 let one: BigInt = One::one();
40 let x_num: BigInt = &p.x * &q.y + &p.y * &q.x;
41 let x_den: BigInt = &one + &self.d * &p.x * &q.x * &p.y * &q.y;
42 let x_den_inv = utils::mod_inverse0(&x_den, &self.q);
43 // let x_den_inv = utils::mod_inverse1(x_den, self.q.clone());
44 // let x_den_inv = utils::mod_inverse2(x_den, self.q.clone());
45 let x: BigInt = utils::modulus(&(&x_num * &x_den_inv), &self.q);
46
47 // y = (y1 * y2 - a * x1 * x2) / (1 - d * x1 * x2 * y1 * y2)
48 let y_num = &p.y * &q.y - &self.a * &p.x * &q.x;
49 let y_den = utils::modulus(&(&one - &self.d * &p.x * &q.x * &p.y * &q.y), &self.q);
50 let y_den_inv = utils::mod_inverse0(&y_den, &self.q);
51 // let y_den_inv = utils::mod_inverse1(y_den, self.q.clone());
52 // let y_den_inv = utils::mod_inverse2(y_den, self.q.clone());
53 let y: BigInt = utils::modulus(&(&y_num * &y_den_inv), &self.q);
54
55 Point { x: x, y: y }
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use super::*;
62 use num_bigint::ToBigInt;
63
64 #[test]
65 fn test_add_same_point() {
66 let p: Point = Point {
67 x: BigInt::parse_bytes(
68 b"17777552123799933955779906779655732241715742912184938656739573121738514868268",
69 10,
70 )
71 .unwrap(),
72 y: BigInt::parse_bytes(
73 b"2626589144620713026669568689430873010625803728049924121243784502389097019475",
74 10,
75 )
76 .unwrap(),
77 };
78 let q: Point = Point {
79 x: BigInt::parse_bytes(
80 b"17777552123799933955779906779655732241715742912184938656739573121738514868268",
81 10,
82 )
83 .unwrap(),
84 y: BigInt::parse_bytes(
85 b"2626589144620713026669568689430873010625803728049924121243784502389097019475",
86 10,
87 )
88 .unwrap(),
89 };
90 let bbjj = Babyjubjub::new();
91 let res = bbjj.add(&p, &q);
92 assert_eq!(
93 res.x.to_string(),
94 "6890855772600357754907169075114257697580319025794532037257385534741338397365"
95 );
96 assert_eq!(
97 res.y.to_string(),
98 "4338620300185947561074059802482547481416142213883829469920100239455078257889"
99 );
100 }
101 #[test]
102 fn test_add_different_points() {
103 let p: Point = Point {
104 x: BigInt::parse_bytes(
105 b"17777552123799933955779906779655732241715742912184938656739573121738514868268",
106 10,
107 )
108 .unwrap(),
109 y: BigInt::parse_bytes(
110 b"2626589144620713026669568689430873010625803728049924121243784502389097019475",
111 10,
112 )
113 .unwrap(),
114 };
115 let q: Point = Point {
116 x: BigInt::parse_bytes(
117 b"16540640123574156134436876038791482806971768689494387082833631921987005038935",
118 10,
119 )
120 .unwrap(),
121 y: BigInt::parse_bytes(
122 b"20819045374670962167435360035096875258406992893633759881276124905556507972311",
123 10,
124 )
125 .unwrap(),
126 };
127 let bbjj = Babyjubjub::new();
128 let res = bbjj.add(&p, &q);
129 assert_eq!(
130 res.x.to_string(),
131 "7916061937171219682591368294088513039687205273691143098332585753343424131937"
132 );
133 assert_eq!(
134 res.y.to_string(),
135 "14035240266687799601661095864649209771790948434046947201833777492504781204499"
136 );
137 }
138}