babyjubjub-rs/src/lib.rs
src/lib.rsRaw
1extern crate generic_array;
2extern crate num;
3extern crate num_bigint;
4extern crate num_traits;
5extern crate rand;
6
7use blake2::{Blake2b, Digest};
8
9use num_bigint::RandBigInt;
10
11use num_bigint::{BigInt, Sign, ToBigInt};
12use num_traits::{One, Zero};
13
14use generic_array::GenericArray;
15
16mod utils;
17
18#[derive(Clone, Debug)]
19pub struct Point {
20 pub x: BigInt,
21 pub y: BigInt,
22}
23pub struct Signature {
24 r_b8: Point,
25 s: BigInt,
26}
27
28pub struct Babyjubjub {
29 d: BigInt,
30 a: BigInt,
31 q: BigInt,
32 b8: Point,
33 order: BigInt,
34 sub_order: BigInt,
35}
36
37impl Babyjubjub {
38 pub fn new() -> Babyjubjub {
39 let d: BigInt = BigInt::parse_bytes(b"168696", 10).unwrap();
40 let a: BigInt = BigInt::parse_bytes(b"168700", 10).unwrap();
41 let q: BigInt = BigInt::parse_bytes(
42 b"21888242871839275222246405745257275088548364400416034343698204186575808495617",
43 10,
44 )
45 .unwrap();
46 let b8: Point = Point {
47 x: BigInt::parse_bytes(
48 b"5299619240641551281634865583518297030282874472190772894086521144482721001553",
49 10,
50 )
51 .unwrap(),
52 y: BigInt::parse_bytes(
53 b"16950150798460657717958625567821834550301663161624707787222815936182638968203",
54 10,
55 )
56 .unwrap(),
57 };
58 let order: BigInt = BigInt::parse_bytes(
59 b"21888242871839275222246405745257275088614511777268538073601725287587578984328",
60 10,
61 )
62 .unwrap();
63 let sub_order: BigInt = &order >> 3;
64
65 Babyjubjub {
66 d: d,
67 a: a,
68 q: q,
69 b8: b8,
70 order: order,
71 sub_order: sub_order,
72 }
73 }
74
75 pub fn add(&self, p: &Point, q: &Point) -> Point {
76 // x = (x1*y2+y1*x2)/(c*(1+d*x1*x2*y1*y2))
77 // y = (y1*y2-x1*x2)/(c*(1-d*x1*x2*y1*y2))
78
79 // x = (x1 * y2 + y1 * x2) / (1 + d * x1 * y1 * y2)
80 let one: BigInt = One::one();
81 let x_num: BigInt = &p.x * &q.y + &p.y * &q.x;
82 let x_den: BigInt = &one + &self.d * &p.x * &q.x * &p.y * &q.y;
83 let x_den_inv = utils::mod_inverse0(&x_den, &self.q);
84 // let x_den_inv = utils::mod_inverse1(x_den, self.q.clone());
85 // let x_den_inv = utils::mod_inverse2(x_den, self.q.clone());
86 let x: BigInt = utils::modulus(&(&x_num * &x_den_inv), &self.q);
87
88 // y = (y1 * y2 - a * x1 * x2) / (1 - d * x1 * x2 * y1 * y2)
89 let y_num = &p.y * &q.y - &self.a * &p.x * &q.x;
90 let y_den = utils::modulus(&(&one - &self.d * &p.x * &q.x * &p.y * &q.y), &self.q);
91 let y_den_inv = utils::mod_inverse0(&y_den, &self.q);
92 // let y_den_inv = utils::mod_inverse1(y_den, self.q.clone());
93 // let y_den_inv = utils::mod_inverse2(y_den, self.q.clone());
94 let y: BigInt = utils::modulus(&(&y_num * &y_den_inv), &self.q);
95
96 Point { x: x, y: y }
97 }
98
99 pub fn mul_scalar(&self, p: Point, n: BigInt) -> Point {
100 // TODO use & in p and n to avoid clones on function call
101 let mut r: Point = Point {
102 x: Zero::zero(),
103 y: One::one(),
104 };
105 let mut rem: BigInt = n;
106 let mut exp: Point = p;
107
108 let zero: BigInt = Zero::zero();
109 let one: BigInt = One::one();
110 while rem != zero {
111 let is_odd = &rem & &one == one;
112 if is_odd == true {
113 r = self.add(&r, &exp);
114 }
115 exp = self.add(&exp, &exp);
116 rem = rem >> 1;
117 }
118 r
119 }
120
121 pub fn new_key(&self) -> BigInt {
122 // https://tools.ietf.org/html/rfc8032#section-5.1.5
123 let mut rng = rand::thread_rng();
124 let sk_raw = rng.gen_biguint(1024).to_bigint().unwrap();
125 println!("sk {:?}", sk_raw.to_string());
126
127 let mut hasher = Blake2b::new();
128 let (_, sk_raw_bytes) = sk_raw.to_bytes_le();
129 hasher.input(sk_raw_bytes);
130 let mut h = hasher.result();
131
132 h[0] = h[0] & 0xF8;
133 h[31] = h[31] & 0x7F;
134 h[31] = h[31] | 0x40;
135
136 let sk = BigInt::from_bytes_le(Sign::Plus, &h[..]);
137
138 sk
139 }
140
141 pub fn sk_to_pk(&self, sk: BigInt) -> Point {
142 // https://tools.ietf.org/html/rfc8032#section-5.1.5
143 // TODO this will be moved into a method of PrivateKey type
144 let pk = &self.mul_scalar(self.b8.clone(), sk);
145 pk.clone()
146 }
147
148 pub fn sign(&self, sk: BigInt, msg: BigInt) -> Signature {
149 // https://tools.ietf.org/html/rfc8032#section-5.1.6
150
151 let mut hasher = Blake2b::new();
152 let (_, sk_bytes) = sk.to_bytes_le();
153 hasher.input(sk_bytes);
154 let mut h = hasher.result(); // h: hash(sk)
155 // s: h[32:64]
156 let s = GenericArray::<u8, generic_array::typenum::U32>::from_mut_slice(&mut h[32..64]);
157
158 let (_, msg_bytes) = msg.to_bytes_le();
159 let r_bytes = utils::concatenate_arrays(s, &msg_bytes);
160 let mut r = BigInt::from_bytes_le(Sign::Plus, &r_bytes[..]);
161 r = r & &self.sub_order;
162 let r8: Point = self.mul_scalar(self.b8.clone(), r.clone());
163 println!("r8 {:?}", r8);
164 let a = &self.sk_to_pk(sk.clone());
165
166 // TODO WARNING!!! [TEMP] use MIMC7 hash function (MIMC7 to be implemented)
167 let hm_input = r8.x + r8.y + &a.x + &a.y + msg; // TEMP
168 let mut hasher = Blake2b::new();
169 let (_, sk_bytes) = sk.to_bytes_le();
170 hasher.input(sk_bytes);
171 let hm = BigInt::from_bytes_le(Sign::Plus, &hasher.result()[..]);
172
173 let mut s = sk << 3;
174 s = hm * s;
175 s = r + s;
176 s = s % &self.sub_order;
177
178 Signature {
179 r_b8: self.b8.clone(),
180 s: s,
181 }
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn test_add_same_point() {
191 let p: Point = Point {
192 x: BigInt::parse_bytes(
193 b"17777552123799933955779906779655732241715742912184938656739573121738514868268",
194 10,
195 )
196 .unwrap(),
197 y: BigInt::parse_bytes(
198 b"2626589144620713026669568689430873010625803728049924121243784502389097019475",
199 10,
200 )
201 .unwrap(),
202 };
203 let q: Point = Point {
204 x: BigInt::parse_bytes(
205 b"17777552123799933955779906779655732241715742912184938656739573121738514868268",
206 10,
207 )
208 .unwrap(),
209 y: BigInt::parse_bytes(
210 b"2626589144620713026669568689430873010625803728049924121243784502389097019475",
211 10,
212 )
213 .unwrap(),
214 };
215 let bbjj = Babyjubjub::new();
216 let res = bbjj.add(&p, &q);
217 assert_eq!(
218 res.x.to_string(),
219 "6890855772600357754907169075114257697580319025794532037257385534741338397365"
220 );
221 assert_eq!(
222 res.y.to_string(),
223 "4338620300185947561074059802482547481416142213883829469920100239455078257889"
224 );
225 }
226 #[test]
227 fn test_add_different_points() {
228 let p: Point = Point {
229 x: BigInt::parse_bytes(
230 b"17777552123799933955779906779655732241715742912184938656739573121738514868268",
231 10,
232 )
233 .unwrap(),
234 y: BigInt::parse_bytes(
235 b"2626589144620713026669568689430873010625803728049924121243784502389097019475",
236 10,
237 )
238 .unwrap(),
239 };
240 let q: Point = Point {
241 x: BigInt::parse_bytes(
242 b"16540640123574156134436876038791482806971768689494387082833631921987005038935",
243 10,
244 )
245 .unwrap(),
246 y: BigInt::parse_bytes(
247 b"20819045374670962167435360035096875258406992893633759881276124905556507972311",
248 10,
249 )
250 .unwrap(),
251 };
252 let bbjj = Babyjubjub::new();
253 let res = bbjj.add(&p, &q);
254 assert_eq!(
255 res.x.to_string(),
256 "7916061937171219682591368294088513039687205273691143098332585753343424131937"
257 );
258 assert_eq!(
259 res.y.to_string(),
260 "14035240266687799601661095864649209771790948434046947201833777492504781204499"
261 );
262 }
263
264 #[test]
265 fn test_mul_scalar() {
266 let p: Point = Point {
267 x: BigInt::parse_bytes(
268 b"17777552123799933955779906779655732241715742912184938656739573121738514868268",
269 10,
270 )
271 .unwrap(),
272 y: BigInt::parse_bytes(
273 b"2626589144620713026669568689430873010625803728049924121243784502389097019475",
274 10,
275 )
276 .unwrap(),
277 };
278 let bbjj = Babyjubjub::new();
279 let res_m = bbjj.mul_scalar(p.clone(), 3.to_bigint().unwrap());
280 let res_a = bbjj.add(&p, &p);
281 let res_a = bbjj.add(&res_a, &p);
282 assert_eq!(res_m.x, res_a.x);
283 assert_eq!(
284 res_m.x.to_string(),
285 "19372461775513343691590086534037741906533799473648040012278229434133483800898"
286 );
287 assert_eq!(
288 res_m.y.to_string(),
289 "9458658722007214007257525444427903161243386465067105737478306991484593958249"
290 );
291
292 let n = BigInt::parse_bytes(
293 b"14035240266687799601661095864649209771790948434046947201833777492504781204499",
294 10,
295 )
296 .unwrap();
297 let res2 = bbjj.mul_scalar(p.clone(), n);
298 assert_eq!(
299 res2.x.to_string(),
300 "17070357974431721403481313912716834497662307308519659060910483826664480189605"
301 );
302 assert_eq!(
303 res2.y.to_string(),
304 "4014745322800118607127020275658861516666525056516280575712425373174125159339"
305 );
306 }
307 #[test]
308 fn test_new_key_sign() {
309 let bbjj = Babyjubjub::new();
310 let sk = bbjj.new_key();
311 println!("sk {:?}", sk);
312 let sig = bbjj.sign(sk, 5.to_bigint().unwrap());
313 println!("sig {:?}", sig.r_b8);
314 println!("sig {:?}", sig.s);
315 }
316}