miracl_core/bls12381/
mpin.rs

1/*
2 * Copyright (c) 2012-2020 MIRACL UK Ltd.
3 *
4 * This file is part of MIRACL Core
5 * (see https://github.com/miracl/core).
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *     http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20use crate::bls12381::big;
21use crate::bls12381::big::BIG;
22use crate::bls12381::ecp;
23use crate::bls12381::ecp::ECP;
24use crate::bls12381::ecp2::ECP2;
25use crate::bls12381::fp12::FP12;
26use crate::bls12381::pair;
27use crate::bls12381::rom;
28use crate::bls12381::fp::FP;
29use crate::bls12381::dbig::DBIG;
30
31use crate::hmac;
32use crate::rand::RAND;
33
34/* MPIN 128-bit API Functions */
35
36/* Configure mode of operation */
37
38pub const EFS: usize = big::MODBYTES as usize;
39pub const EGS: usize = big::MODBYTES as usize;
40pub const BAD_PARAMS: isize = -11;
41pub const INVALID_POINT: isize = -14;
42pub const WRONG_ORDER: isize = -18;
43pub const BAD_PIN: isize = -19;
44pub const SHA256: usize = 32;
45pub const SHA384: usize = 48;
46pub const SHA512: usize = 64;
47
48/* Configure your PIN here */
49
50pub const MAXPIN: i32 = 10000; /* PIN less than this */
51pub const PBLEN: i32 = 14; /* Number of bits in PIN */
52
53fn ceil(a: usize,b: usize) -> usize {
54    (a-1)/b+1
55}
56
57#[allow(non_snake_case)]
58pub fn encode_to_curve(dst: &[u8],id: &[u8],hcid: &mut [u8]) {
59    let q = BIG::new_ints(&rom::MODULUS);
60    let k=q.nbits();
61    let r = BIG::new_ints(&rom::CURVE_ORDER);
62    let m=r.nbits();
63    let el=ceil(k+ceil(m,2),8);
64    let mut okm: [u8;512]=[0;512];
65    hmac::xmd_expand(hmac::MC_SHA2,ecp::HASH_TYPE,&mut okm,el,&dst,&id);
66    let mut fd: [u8;256]=[0;256];
67    for j in 0..el {
68        fd[j]=okm[j];
69    }
70	let mut dx=DBIG::frombytes(&fd[0..el]);
71    let u=FP::new_big(&dx.dmod(&q));
72    let mut P=ECP::map2point(&u);
73    P.cfp();
74    P.affine();
75    P.tobytes(hcid,false);
76}
77
78/* create random secret S */
79pub fn random_generate(rng: &mut impl RAND, s: &mut [u8]) -> isize {
80    let r = BIG::new_ints(&rom::CURVE_ORDER);
81    let sc = BIG::randtrunc(&r, 16 * ecp::AESKEY, rng);
82    sc.tobytes(s);
83    0
84}
85
86/* Extract PIN from TOKEN for identity CID */
87#[allow(non_snake_case)]
88pub fn extract_pin(cid: &[u8], pin: i32, token: &mut [u8]) -> isize {
89    let mut P = ECP::frombytes(&token);
90    if P.is_infinity() {
91        return INVALID_POINT;
92    }
93    let mut R = ECP::frombytes(&cid);
94    if R.is_infinity() {
95        return INVALID_POINT;
96    }
97
98    R = R.pinmul(pin%MAXPIN, PBLEN);
99    P.sub(&R);
100    P.tobytes(token, false);
101    0
102}
103
104/* Implement step 2 on client side of MPin protocol */
105#[allow(non_snake_case)]
106pub fn client_2(x: &[u8], y: &[u8], sec: &mut [u8]) -> isize {
107    let r = BIG::new_ints(&rom::CURVE_ORDER);
108    let mut P = ECP::frombytes(sec);
109    if P.is_infinity() {
110        return INVALID_POINT;
111    }
112
113    let mut px = BIG::frombytes(x);
114    let py = BIG::frombytes(y);
115    px.add(&py);
116    px.rmod(&r);
117
118    P = pair::g1mul(&P, &px);
119    P.neg();
120    P.tobytes(sec, false);
121    0
122}
123
124/* Client secret CST=S*H(CID) where CID is client ID and S is master secret */
125#[allow(non_snake_case)]
126pub fn get_client_secret(s: &mut [u8], idhtc: &[u8], cst: &mut [u8]) -> isize {
127    let sx=BIG::frombytes(s);
128    let P=ECP::frombytes(idhtc);
129    if P.is_infinity() {
130        return INVALID_POINT;
131    }
132    pair::g1mul(&P, &sx).tobytes(cst, false);
133    0
134}
135
136/* Implement step 1 on client side of MPin protocol */
137#[allow(non_snake_case)]
138pub fn client_1(
139    cid: &[u8],
140    rng: Option<&mut impl RAND>,
141    x: &mut [u8],
142    pin: usize,
143    token: &[u8],
144    sec: &mut [u8],
145    xid: &mut [u8]
146) -> isize {
147    let r = BIG::new_ints(&rom::CURVE_ORDER);
148    let sx: BIG;
149
150    if let Some(rd) = rng {
151        sx = BIG::randtrunc(&r, 16 * ecp::AESKEY, rd);
152        sx.tobytes(x);
153    } else {
154        sx = BIG::frombytes(x);
155    }
156    let mut P=ECP::frombytes(cid);
157    if P.is_infinity() {
158        return INVALID_POINT;
159    }
160
161    let mut T = ECP::frombytes(&token);
162    if T.is_infinity() {
163        return INVALID_POINT;
164    }
165
166    let W = P.pinmul((pin as i32) % MAXPIN, PBLEN);
167    T.add(&W);
168
169    P = pair::g1mul(&P, &sx);
170    P.tobytes(xid, false);
171
172    T.tobytes(sec, false);
173    0
174}
175
176
177/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */
178#[allow(non_snake_case)]
179pub fn get_server_secret(s: &[u8], sst: &mut [u8]) -> isize {
180    let mut Q = ECP2::generator();
181    let sc = BIG::frombytes(s);
182    Q = pair::g2mul(&Q, &sc);
183    Q.tobytes(sst,false);
184    0
185}
186
187/* Implement step 2 of MPin protocol on server side */
188#[allow(non_snake_case)]
189pub fn server(
190    hid: &[u8],
191    y: &[u8],
192    sst: &[u8],
193    xid: &[u8],
194    msec: &[u8],
195) -> isize {
196    let Q = ECP2::generator();
197    let sQ = ECP2::frombytes(&sst);
198    if sQ.is_infinity() {
199        return INVALID_POINT;
200    }
201    let mut R = ECP::frombytes(&xid);
202    if R.is_infinity() {
203        return INVALID_POINT;
204    }
205
206    let sy = BIG::frombytes(&y);
207    let mut P = ECP::frombytes(&hid);
208    if P.is_infinity() {
209        return INVALID_POINT;
210    }
211
212    P = pair::g1mul(&P, &sy);
213    P.add(&R);
214    R = ECP::frombytes(&msec);
215    if R.is_infinity() {
216        return INVALID_POINT;
217    }
218
219    let mut g: FP12;
220    g = pair::ate2(&Q, &R, &sQ, &P);
221    g = pair::fexp(&g);
222
223    if !g.isunity() {
224        return BAD_PIN;
225    }
226    0
227}
228