arnaucube
arnaucube/babyjubjub-rsPublic Self-hosted repository
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}