http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version3/c/hash.c ---------------------------------------------------------------------- diff --git a/version3/c/hash.c b/version3/c/hash.c new file mode 100644 index 0000000..44fe4b0 --- /dev/null +++ b/version3/c/hash.c @@ -0,0 +1,606 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* + * Implementation of the Secure Hashing Algorithm (SHA-256/384/512 and SHA3) + * + * Generates a message digest. It should be impossible to come + * come up with two messages that hash to the same value ("collision free"). + * + * For use with byte-oriented messages only. Could/Should be speeded + * up by unwinding loops in HASH_transform(), and assembly patches. + */ + +#include "arch.h" +#include "amcl.h" + + +#define H0_256 0x6A09E667L +#define H1_256 0xBB67AE85L +#define H2_256 0x3C6EF372L +#define H3_256 0xA54FF53AL +#define H4_256 0x510E527FL +#define H5_256 0x9B05688CL +#define H6_256 0x1F83D9ABL +#define H7_256 0x5BE0CD19L + +static const unsign32 K_256[64]= +{ + 0x428a2f98L,0x71374491L,0xb5c0fbcfL,0xe9b5dba5L,0x3956c25bL,0x59f111f1L,0x923f82a4L,0xab1c5ed5L, + 0xd807aa98L,0x12835b01L,0x243185beL,0x550c7dc3L,0x72be5d74L,0x80deb1feL,0x9bdc06a7L,0xc19bf174L, + 0xe49b69c1L,0xefbe4786L,0x0fc19dc6L,0x240ca1ccL,0x2de92c6fL,0x4a7484aaL,0x5cb0a9dcL,0x76f988daL, + 0x983e5152L,0xa831c66dL,0xb00327c8L,0xbf597fc7L,0xc6e00bf3L,0xd5a79147L,0x06ca6351L,0x14292967L, + 0x27b70a85L,0x2e1b2138L,0x4d2c6dfcL,0x53380d13L,0x650a7354L,0x766a0abbL,0x81c2c92eL,0x92722c85L, + 0xa2bfe8a1L,0xa81a664bL,0xc24b8b70L,0xc76c51a3L,0xd192e819L,0xd6990624L,0xf40e3585L,0x106aa070L, + 0x19a4c116L,0x1e376c08L,0x2748774cL,0x34b0bcb5L,0x391c0cb3L,0x4ed8aa4aL,0x5b9cca4fL,0x682e6ff3L, + 0x748f82eeL,0x78a5636fL,0x84c87814L,0x8cc70208L,0x90befffaL,0xa4506cebL,0xbef9a3f7L,0xc67178f2L +}; + +#define PAD 0x80 +#define ZERO 0 + +/* functions */ + +#define S(m,n,x) (((x)>>n) | ((x)<<(m-n))) +#define R(n,x) ((x)>>n) + +#define Ch(x,y,z) ((x&y)^(~(x)&z)) +#define Maj(x,y,z) ((x&y)^(x&z)^(y&z)) +#define Sig0_256(x) (S(32,2,x)^S(32,13,x)^S(32,22,x)) +#define Sig1_256(x) (S(32,6,x)^S(32,11,x)^S(32,25,x)) +#define theta0_256(x) (S(32,7,x)^S(32,18,x)^R(3,x)) +#define theta1_256(x) (S(32,17,x)^S(32,19,x)^R(10,x)) + +#define Sig0_512(x) (S(64,28,x)^S(64,34,x)^S(64,39,x)) +#define Sig1_512(x) (S(64,14,x)^S(64,18,x)^S(64,41,x)) +#define theta0_512(x) (S(64,1,x)^S(64,8,x)^R(7,x)) +#define theta1_512(x) (S(64,19,x)^S(64,61,x)^R(6,x)) + + +/* SU= 72 */ +static void HASH256_transform(hash256 *sh) +{ + /* basic transformation step */ + unsign32 a,b,c,d,e,f,g,h,t1,t2; + int j; + for (j=16; j<64; j++) + sh->w[j]=theta1_256(sh->w[j-2])+sh->w[j-7]+theta0_256(sh->w[j-15])+sh->w[j-16]; + + a=sh->h[0]; + b=sh->h[1]; + c=sh->h[2]; + d=sh->h[3]; + e=sh->h[4]; + f=sh->h[5]; + g=sh->h[6]; + h=sh->h[7]; + + for (j=0; j<64; j++) + { + /* 64 times - mush it up */ + t1=h+Sig1_256(e)+Ch(e,f,g)+K_256[j]+sh->w[j]; + t2=Sig0_256(a)+Maj(a,b,c); + h=g; + g=f; + f=e; + e=d+t1; + d=c; + c=b; + b=a; + a=t1+t2; + } + + sh->h[0]+=a; + sh->h[1]+=b; + sh->h[2]+=c; + sh->h[3]+=d; + sh->h[4]+=e; + sh->h[5]+=f; + sh->h[6]+=g; + sh->h[7]+=h; +} + +/* Initialise Hash function */ +void HASH256_init(hash256 *sh) +{ + /* re-initialise */ + int i; + for (i=0; i<64; i++) sh->w[i]=0L; + sh->length[0]=sh->length[1]=0L; + sh->h[0]=H0_256; + sh->h[1]=H1_256; + sh->h[2]=H2_256; + sh->h[3]=H3_256; + sh->h[4]=H4_256; + sh->h[5]=H5_256; + sh->h[6]=H6_256; + sh->h[7]=H7_256; + + sh->hlen=32; +} + +/* process a single byte */ +void HASH256_process(hash256 *sh,int byt) +{ + /* process the next message byte */ + int cnt; + cnt=(int)((sh->length[0]/32)%16); + + sh->w[cnt]<<=8; + sh->w[cnt]|=(unsign32)(byt&0xFF); + + sh->length[0]+=8; + if (sh->length[0]==0L) + { + sh->length[1]++; + sh->length[0]=0L; + } + if ((sh->length[0]%512)==0) HASH256_transform(sh); +} + +/* SU= 24 */ +/* Generate 32-byte Hash */ +void HASH256_hash(hash256 *sh,char *digest) +{ + /* pad message and finish - supply digest */ + int i; + unsign32 len0,len1; + len0=sh->length[0]; + len1=sh->length[1]; + HASH256_process(sh,PAD); + while ((sh->length[0]%512)!=448) HASH256_process(sh,ZERO); + sh->w[14]=len1; + sh->w[15]=len0; + HASH256_transform(sh); + for (i=0; i<sh->hlen; i++) + { + /* convert to bytes */ + digest[i]=(char)((sh->h[i/4]>>(8*(3-i%4))) & 0xffL); + } + HASH256_init(sh); +} + + +#define H0_512 0x6a09e667f3bcc908 +#define H1_512 0xbb67ae8584caa73b +#define H2_512 0x3c6ef372fe94f82b +#define H3_512 0xa54ff53a5f1d36f1 +#define H4_512 0x510e527fade682d1 +#define H5_512 0x9b05688c2b3e6c1f +#define H6_512 0x1f83d9abfb41bd6b +#define H7_512 0x5be0cd19137e2179 + +#define H8_512 0xcbbb9d5dc1059ed8 +#define H9_512 0x629a292a367cd507 +#define HA_512 0x9159015a3070dd17 +#define HB_512 0x152fecd8f70e5939 +#define HC_512 0x67332667ffc00b31 +#define HD_512 0x8eb44a8768581511 +#define HE_512 0xdb0c2e0d64f98fa7 +#define HF_512 0x47b5481dbefa4fa4 + +/* */ + +static const unsign64 K_512[80]= +{ + 0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc, + 0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118, + 0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694, + 0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65, + 0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5, + 0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70, + 0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df, + 0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b, + 0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30, + 0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec, + 0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b, + 0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178, + 0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b, + 0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817 +}; + + +static void HASH512_transform(hash512 *sh) +{ + /* basic transformation step */ + unsign64 a,b,c,d,e,f,g,h,t1,t2; + int j; + for (j=16; j<80; j++) + sh->w[j]=theta1_512(sh->w[j-2])+sh->w[j-7]+theta0_512(sh->w[j-15])+sh->w[j-16]; + + a=sh->h[0]; + b=sh->h[1]; + c=sh->h[2]; + d=sh->h[3]; + e=sh->h[4]; + f=sh->h[5]; + g=sh->h[6]; + h=sh->h[7]; + + for (j=0; j<80; j++) + { + /* 80 times - mush it up */ + t1=h+Sig1_512(e)+Ch(e,f,g)+K_512[j]+sh->w[j]; + t2=Sig0_512(a)+Maj(a,b,c); + h=g; + g=f; + f=e; + e=d+t1; + d=c; + c=b; + b=a; + a=t1+t2; + } + sh->h[0]+=a; + sh->h[1]+=b; + sh->h[2]+=c; + sh->h[3]+=d; + sh->h[4]+=e; + sh->h[5]+=f; + sh->h[6]+=g; + sh->h[7]+=h; +} + +void HASH384_init(hash384 *sh) +{ + /* re-initialise */ + int i; + for (i=0; i<80; i++) sh->w[i]=0; + sh->length[0]=sh->length[1]=0; + sh->h[0]=H8_512; + sh->h[1]=H9_512; + sh->h[2]=HA_512; + sh->h[3]=HB_512; + sh->h[4]=HC_512; + sh->h[5]=HD_512; + sh->h[6]=HE_512; + sh->h[7]=HF_512; + + sh->hlen=48; + +} + +void HASH384_process(hash384 *sh,int byt) +{ + /* process the next message byte */ + HASH512_process(sh,byt); +} + +void HASH384_hash(hash384 *sh,char *hash) +{ + /* pad message and finish - supply digest */ + HASH512_hash(sh,hash); +} + +void HASH512_init(hash512 *sh) +{ + /* re-initialise */ + int i; + + for (i=0; i<80; i++) sh->w[i]=0; + sh->length[0]=sh->length[1]=0; + sh->h[0]=H0_512; + sh->h[1]=H1_512; + sh->h[2]=H2_512; + sh->h[3]=H3_512; + sh->h[4]=H4_512; + sh->h[5]=H5_512; + sh->h[6]=H6_512; + sh->h[7]=H7_512; + + sh->hlen=64; +} + +void HASH512_process(hash512 *sh,int byt) +{ + /* process the next message byte */ + int cnt; + + cnt=(int)((sh->length[0]/64)%16); + + sh->w[cnt]<<=8; + sh->w[cnt]|=(unsign64)(byt&0xFF); + + sh->length[0]+=8; + if (sh->length[0]==0L) + { + sh->length[1]++; + sh->length[0]=0L; + } + if ((sh->length[0]%1024)==0) HASH512_transform(sh); +} + +void HASH512_hash(hash512 *sh,char *hash) +{ + /* pad message and finish - supply digest */ + int i; + unsign64 len0,len1; + len0=sh->length[0]; + len1=sh->length[1]; + HASH512_process(sh,PAD); + while ((sh->length[0]%1024)!=896) HASH512_process(sh,ZERO); + sh->w[14]=len1; + sh->w[15]=len0; + HASH512_transform(sh); + for (i=0; i<sh->hlen; i++) + { + /* convert to bytes */ + hash[i]=(char)((sh->h[i/8]>>(8*(7-i%8))) & 0xffL); + } + HASH512_init(sh); +} + + + +/* SHA3 */ + +#define SHA3_ROUNDS 24 +#define rotl(x,n) (((x)<<n) | ((x)>>(64-n))) + +/* round constants */ + +static const unsign64 RC[24]= +{ + 0x0000000000000001UL,0x0000000000008082UL,0x800000000000808AUL,0x8000000080008000UL, + 0x000000000000808BUL,0x0000000080000001UL,0x8000000080008081UL,0x8000000000008009UL, + 0x000000000000008AUL,0x0000000000000088UL,0x0000000080008009UL,0x000000008000000AUL, + 0x000000008000808BUL,0x800000000000008BUL,0x8000000000008089UL,0x8000000000008003UL, + 0x8000000000008002UL,0x8000000000000080UL,0x000000000000800AUL,0x800000008000000AUL, + 0x8000000080008081UL,0x8000000000008080UL,0x0000000080000001UL,0x8000000080008008UL +}; + +/* permutation */ + +static void SHA3_transform(sha3 *sh) +{ + int i,j,k; + unsign64 C[5],D[5],B[5][5]; + + for (k=0; k<SHA3_ROUNDS; k++) + { + C[0]=sh->S[0][0]^sh->S[0][1]^sh->S[0][2]^sh->S[0][3]^sh->S[0][4]; + C[1]=sh->S[1][0]^sh->S[1][1]^sh->S[1][2]^sh->S[1][3]^sh->S[1][4]; + C[2]=sh->S[2][0]^sh->S[2][1]^sh->S[2][2]^sh->S[2][3]^sh->S[2][4]; + C[3]=sh->S[3][0]^sh->S[3][1]^sh->S[3][2]^sh->S[3][3]^sh->S[3][4]; + C[4]=sh->S[4][0]^sh->S[4][1]^sh->S[4][2]^sh->S[4][3]^sh->S[4][4]; + + D[0]=C[4]^rotl(C[1],1); + D[1]=C[0]^rotl(C[2],1); + D[2]=C[1]^rotl(C[3],1); + D[3]=C[2]^rotl(C[4],1); + D[4]=C[3]^rotl(C[0],1); + + for (i=0; i<5; i++) + for (j=0; j<5; j++) + sh->S[i][j]^=D[i]; /* let the compiler unroll it! */ + + B[0][0]=sh->S[0][0]; + B[1][3]=rotl(sh->S[0][1],36); + B[2][1]=rotl(sh->S[0][2],3); + B[3][4]=rotl(sh->S[0][3],41); + B[4][2]=rotl(sh->S[0][4],18); + + B[0][2]=rotl(sh->S[1][0],1); + B[1][0]=rotl(sh->S[1][1],44); + B[2][3]=rotl(sh->S[1][2],10); + B[3][1]=rotl(sh->S[1][3],45); + B[4][4]=rotl(sh->S[1][4],2); + + B[0][4]=rotl(sh->S[2][0],62); + B[1][2]=rotl(sh->S[2][1],6); + B[2][0]=rotl(sh->S[2][2],43); + B[3][3]=rotl(sh->S[2][3],15); + B[4][1]=rotl(sh->S[2][4],61); + + B[0][1]=rotl(sh->S[3][0],28); + B[1][4]=rotl(sh->S[3][1],55); + B[2][2]=rotl(sh->S[3][2],25); + B[3][0]=rotl(sh->S[3][3],21); + B[4][3]=rotl(sh->S[3][4],56); + + B[0][3]=rotl(sh->S[4][0],27); + B[1][1]=rotl(sh->S[4][1],20); + B[2][4]=rotl(sh->S[4][2],39); + B[3][2]=rotl(sh->S[4][3],8); + B[4][0]=rotl(sh->S[4][4],14); + + for (i=0; i<5; i++) + for (j=0; j<5; j++) + sh->S[i][j]=B[i][j]^(~B[(i+1)%5][j]&B[(i+2)%5][j]); + + sh->S[0][0]^=RC[k]; + } +} + +/* Re-Initialize. olen is output length in bytes - + should be 28, 32, 48 or 64 (224, 256, 384, 512 bits resp.) */ + +void SHA3_init(sha3 *sh,int olen) +{ + int i,j; + for (i=0; i<5; i++) + for (j=0; j<5; j++) + sh->S[i][j]=0; /* 5x5x8 bytes = 200 bytes of state */ + sh->length=0; + sh->len=olen; + sh->rate=200-2*olen; /* number of bytes consumed in one gulp. Note that some bytes in the + state ("capacity") are not touched. Gulps are smaller for larger digests. + Important that olen<rate */ +} + +/* process a single byte */ +void SHA3_process(sha3 *sh,int byt) +{ + int cnt=(int)(sh->length%sh->rate); + int i,j,b=cnt%8; + cnt/=8; + i=cnt%5; + j=cnt/5; /* process by columns! */ + sh->S[i][j]^=((unsign64)byt<<(8*b)); + sh->length++; + if (sh->length%sh->rate==0) SHA3_transform(sh); +} + +/* squeeze the sponge */ +void SHA3_squeeze(sha3 *sh,char *buff,int len) +{ + int done,i,j,k,m=0; + unsign64 el; + /* extract by columns */ + done=0; + for (;;) + { + for (j=0; j<5; j++) + { + for (i=0; i<5; i++) + { + el=sh->S[i][j]; + for (k=0; k<8; k++) + { + buff[m++]=(el&0xff); + if (m>=len || m%sh->rate==0) + { + done=1; + break; + } + el>>=8; + } + if (done) break; + } + if (done) break; + } + if (m>=len) break; + done=0; + SHA3_transform(sh); + } +} + +void SHA3_hash(sha3 *sh,char *hash) +{ + /* generate a SHA3 hash of appropriate size */ + int q=sh->rate-(sh->length%sh->rate); + if (q==1) SHA3_process(sh,0x86); + else + { + SHA3_process(sh,0x06); /* 0x06 for SHA-3 */ + while ((int)sh->length%sh->rate!=sh->rate-1) SHA3_process(sh,0x00); + SHA3_process(sh,0x80); /* this will force a final transform */ + } + SHA3_squeeze(sh,hash,sh->len); +} + +void SHA3_shake(sha3 *sh,char *buff,int len) +{ + /* SHAKE out a buffer of variable length len */ + int q=sh->rate-(sh->length%sh->rate); + if (q==1) SHA3_process(sh,0x9f); + else + { + SHA3_process(sh,0x1f); // 0x06 for SHA-3 !!!! + while ((int) sh->length%sh->rate!=sh->rate-1) SHA3_process(sh,0x00); + SHA3_process(sh,0x80); /* this will force a final transform */ + } + SHA3_squeeze(sh,buff,len); +} + + +/* test program: should produce digest + +160 bit + +84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1 + +256 bit + +248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1 + +512 bit + +8e959b75dae313da 8cf4f72814fc143f 8f7779c6eb9f7fa1 7299aeadb6889018 +501d289e4900f7e4 331b99dec4b5433a c7d329eeb6dd2654 5e96e55b874be909 + +384 bit + +09330c33f71147e8 3d192fc782cd1b47 53111b173b3b05d2 2fa08086e3b0f712 +fcc7c71a557e2db9 66c3e9fa91746039 +*/ +/* +#include <stdio.h> + +char test160[]="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; +char test256[]="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; +char test512[]="abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; + +int main() +{ + char digest[100]; + int i; + + hash256 sh256; + hash384 sh384; + hash512 sh512; + sha3 SHA3; + + HASH256_init(&sh256); + for (i=0;test256[i]!=0;i++) HASH256_process(&sh256,test256[i]); + HASH256_hash(&sh256,digest); + for (i=0;i<32;i++) printf("%02x",(unsigned char)digest[i]); + printf("\n"); + + HASH384_init(&sh384); + for (i=0;test512[i]!=0;i++) HASH384_process(&sh384,test512[i]); + HASH384_hash(&sh384,digest); + for (i=0;i<48;i++) printf("%02x",(unsigned char)digest[i]); + printf("\n"); + + HASH512_init(&sh512); + for (i=0;test512[i]!=0;i++) HASH512_process(&sh512,test512[i]); + HASH512_hash(&sh512,digest); + for (i=0;i<64;i++) printf("%02x",(unsigned char)digest[i]); + printf("\n"); + + SHA3_init(&SHA3,SHA3_HASH256); + for (i=0;test512[i]!=0;i++) SHA3_process(&SHA3,test512[i]); + SHA3_hash(&SHA3,digest); + for (i=0;i<32;i++) printf("%02x",(unsigned char)digest[i]); + printf("\n"); + + SHA3_init(&SHA3,SHA3_HASH512); + for (i=0;test512[i]!=0;i++) SHA3_process(&SHA3,test512[i]); + SHA3_hash(&SHA3,digest); + for (i=0;i<64;i++) printf("%02x",(unsigned char)digest[i]); + printf("\n"); + + SHA3_init(&SHA3,SHAKE256); + for (i=0;test512[i]!=0;i++) SHA3_process(&SHA3,test512[i]); + SHA3_shake(&SHA3,digest,72); + for (i=0;i<72;i++) printf("%02x",(unsigned char)digest[i]); + printf("\n"); + + + return 0; +} + +*/
http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version3/c/mpin.c ---------------------------------------------------------------------- diff --git a/version3/c/mpin.c b/version3/c/mpin.c new file mode 100644 index 0000000..9d5d983 --- /dev/null +++ b/version3/c/mpin.c @@ -0,0 +1,933 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* MPIN Functions */ + +/* Version 3.0 - supports Time Permits */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "mpin_ZZZ.h" + +#define ROUNDUP(a,b) ((a)-1)/(b)+1 + +/* Special mpin hashing */ +static void mpin_hash(int sha,FP4_YYY *f, ECP_ZZZ *P,octet *w) +{ + int i; + BIG_XXX x,y; + char h[64]; + hash256 sha256; + hash512 sha512; + char t[6*MODBYTES_XXX]; // to hold 6 BIGs + int hlen=sha; + + + FP_YYY_redc(x,&(f->a.a)); + BIG_XXX_toBytes(&t[0],x); + FP_YYY_redc(x,&(f->a.b)); + BIG_XXX_toBytes(&t[MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.a)); + BIG_XXX_toBytes(&t[2*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.b)); + BIG_XXX_toBytes(&t[3*MODBYTES_XXX],x); + ECP_ZZZ_get(x,y,P); + BIG_XXX_toBytes(&t[4*MODBYTES_XXX],x); + BIG_XXX_toBytes(&t[5*MODBYTES_XXX],y); + + OCT_empty(w); + switch (sha) + { + case SHA256: + HASH256_init(&sha256); + for (i=0; i<6*MODBYTES_XXX; i++) HASH256_process(&sha256,t[i]); + HASH256_hash(&sha256,h); + break; + case SHA384: + HASH384_init(&sha512); + for (i=0; i<6*MODBYTES_XXX; i++) HASH384_process(&sha512,t[i]); + HASH384_hash(&sha512,h); + break; + case SHA512: + HASH512_init(&sha512); + for (i=0; i<6*MODBYTES_XXX; i++) HASH512_process(&sha512,t[i]); + HASH512_hash(&sha512,h); + break; + } + + OCT_jbytes(w,h,AESKEY_ZZZ); + for (i=0; i<hlen; i++) h[i]=0; +} + +/* these next two functions help to implement elligator squared - http://eprint.iacr.org/2014/043 */ +/* maps a random u to a point on the curve */ +static void map(ECP_ZZZ *P,BIG_XXX u,int cb) +{ + BIG_XXX x,q; + + BIG_XXX_rcopy(q,Modulus_YYY); + BIG_XXX_copy(x,u); + BIG_XXX_mod(x,q); + + while (!ECP_ZZZ_setx(P,x,cb)) + { + BIG_XXX_inc(x,1); + BIG_XXX_norm(x); + } +} + +/* returns u derived from P. Random value in range 1 to return value should then be added to u */ +static int unmap(BIG_XXX u,int *cb,ECP_ZZZ *P) +{ + int s,r=0; + BIG_XXX x; + + s=ECP_ZZZ_get(x,x,P); + BIG_XXX_copy(u,x); + do + { + BIG_XXX_dec(u,1); + BIG_XXX_norm(u); + r++; + } + while (!ECP_ZZZ_setx(P,u,s)); + ECP_ZZZ_setx(P,x,s); + + *cb=s; + + return r; +} + +/* these next two functions implement elligator squared - http://eprint.iacr.org/2014/043 */ +/* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} */ +/* Note that u and v are indistinguisible from random strings */ +int MPIN_ZZZ_ENCODING(csprng *RNG,octet *E) +{ + int rn,m,su,sv,res=0; + + BIG_XXX q,u,v; + ECP_ZZZ P,W; + + if (!ECP_ZZZ_fromOctet(&P,E)) res=MPIN_INVALID_POINT; + if (res==0) + { + BIG_XXX_rcopy(q,Modulus_YYY); + + BIG_XXX_randomnum(u,q,RNG); + + su=RAND_byte(RNG); + if (su<0) su=-su; + su%=2; + map(&W,u,su); + ECP_ZZZ_sub(&P,&W); + + rn=unmap(v,&sv,&P); + m=RAND_byte(RNG); + if (m<0) m=-m; + m%=rn; + BIG_XXX_inc(v,m+1); + E->val[0]=su+2*sv; + BIG_XXX_toBytes(&(E->val[1]),u); + BIG_XXX_toBytes(&(E->val[PFS_ZZZ+1]),v); + } + return res; +} + +int MPIN_ZZZ_DECODING(octet *D) +{ + int su,sv; + BIG_XXX u,v; + ECP_ZZZ P,W; + int res=0; + + if ((D->val[0]&0x04)!=0) res=MPIN_INVALID_POINT; + if (res==0) + { + + BIG_XXX_fromBytes(u,&(D->val[1])); + BIG_XXX_fromBytes(v,&(D->val[PFS_ZZZ+1])); + + su=D->val[0]&1; + sv=(D->val[0]>>1)&1; + map(&W,u,su); + map(&P,v,sv); + ECP_ZZZ_add(&P,&W); + ECP_ZZZ_toOctet(D,&P,false); + } + + return res; +} + +/* R=R1+R2 in group G1 */ +int MPIN_ZZZ_RECOMBINE_G1(octet *R1,octet *R2,octet *R) +{ + ECP_ZZZ P,T; + int res=0; + if (res==0) + { + if (!ECP_ZZZ_fromOctet(&P,R1)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&T,R2)) res=MPIN_INVALID_POINT; + } + if (res==0) + { + ECP_ZZZ_add(&P,&T); + ECP_ZZZ_toOctet(R,&P,false); + } + return res; +} + +/* W=W1+W2 in group G2 */ +int MPIN_ZZZ_RECOMBINE_G2(octet *W1,octet *W2,octet *W) +{ + ECP2_ZZZ Q,T; + int res=0; + if (!ECP2_ZZZ_fromOctet(&Q,W1)) res=MPIN_INVALID_POINT; + if (!ECP2_ZZZ_fromOctet(&T,W2)) res=MPIN_INVALID_POINT; + if (res==0) + { + ECP2_ZZZ_add(&Q,&T); + ECP2_ZZZ_toOctet(W,&Q); + } + return res; +} + +/* create random secret S */ +int MPIN_ZZZ_RANDOM_GENERATE(csprng *RNG,octet* S) +{ + BIG_XXX r,s; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_randomnum(s,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(s,2*AES_S); +#endif + BIG_XXX_toBytes(S->val,s); + S->len=MODBYTES_XXX; + return 0; +} + +/* Extract PIN from TOKEN for identity CID */ +int MPIN_ZZZ_EXTRACT_PIN(int sha,octet *CID,int pin,octet *TOKEN) +{ + pin%=MAXPIN; + return MPIN_ZZZ_EXTRACT_FACTOR(sha,CID,pin,PBLEN,TOKEN); +} + +/* Extract a factor < 32 bits for identity CID */ +int MPIN_ZZZ_EXTRACT_FACTOR(int sha,octet *CID,int factor,int facbits,octet *TOKEN) +{ + ECP_ZZZ P,R; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + if (!ECP_ZZZ_fromOctet(&P,TOKEN)) res=MPIN_INVALID_POINT; + if (res==0) + { + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&R,&H); + + ECP_ZZZ_pinmul(&R,factor,facbits); + ECP_ZZZ_sub(&P,&R); + + ECP_ZZZ_toOctet(TOKEN,&P,false); + } + return res; +} + +/* Extract a factor < 32 bits for identity CID */ +int MPIN_ZZZ_RESTORE_FACTOR(int sha,octet *CID,int factor,int facbits,octet *TOKEN) +{ + ECP_ZZZ P,R; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + if (!ECP_ZZZ_fromOctet(&P,TOKEN)) res=MPIN_INVALID_POINT; + if (res==0) + { + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&R,&H); + + ECP_ZZZ_pinmul(&R,factor,facbits); + ECP_ZZZ_add(&P,&R); + + ECP_ZZZ_toOctet(TOKEN,&P,false); + } + return res; +} + +/* Implement step 2 on client side of MPin protocol - SEC=-(x+y)*SEC */ +int MPIN_ZZZ_CLIENT_2(octet *X,octet *Y,octet *SEC) +{ + BIG_XXX px,py,r; + ECP_ZZZ P; + int res=0; + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (!ECP_ZZZ_fromOctet(&P,SEC)) res=MPIN_INVALID_POINT; + if (res==0) + { + BIG_XXX_fromBytes(px,X->val); + BIG_XXX_fromBytes(py,Y->val); + BIG_XXX_add(px,px,py); + BIG_XXX_mod(px,r); + PAIR_ZZZ_G1mul(&P,px); + ECP_ZZZ_neg(&P); + ECP_ZZZ_toOctet(SEC,&P,false); + } + return res; +} + +/* + W=x*H(G); + if RNG == NULL then X is passed in + if RNG != NULL the X is passed out + if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve +*/ + +int MPIN_ZZZ_GET_G1_MULTIPLE(csprng *RNG,int type,octet *X,octet *G,octet *W) +{ + ECP_ZZZ P; + BIG_XXX r,x; + int res=0; + if (RNG!=NULL) + { + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + BIG_XXX_fromBytes(x,X->val); + + if (type==0) + { + if (!ECP_ZZZ_fromOctet(&P,G)) res=MPIN_INVALID_POINT; + } + else + { + ECP_ZZZ_mapit(&P,G); + } + + if (res==0) + { + PAIR_ZZZ_G1mul(&P,x); + ECP_ZZZ_toOctet(W,&P,false); + } + return res; +} + +/* + if RNG == NULL then X is passed in + if RNG != NULL the X is passed out + W=x*G where G is point on the curve + if type==1 W=(x^-1)G +*/ + +int MPIN_ZZZ_GET_G2_MULTIPLE(csprng *RNG,int type,octet *X,octet *G,octet *W) +{ + ECP2_ZZZ P; + BIG_XXX r,x; + int res=0; + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (RNG!=NULL) + { + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + { + BIG_XXX_fromBytes(x,X->val); + if (type==1) BIG_XXX_invmodp(x,x,r); + } + + if (!ECP2_ZZZ_fromOctet(&P,G)) res=MPIN_INVALID_POINT; + + if (res==0) + { + PAIR_ZZZ_G2mul(&P,x); + ECP2_ZZZ_toOctet(W,&P); + } + return res; +} + + + +/* Client secret CST=s*H(CID) where CID is client ID and s is master secret */ +/* CID is hashed externally */ +int MPIN_ZZZ_GET_CLIENT_SECRET(octet *S,octet *CID,octet *CST) +{ + return MPIN_ZZZ_GET_G1_MULTIPLE(NULL,1,S,CID,CST); +} + +/* Implement step 1 on client side of MPin protocol */ +int MPIN_ZZZ_CLIENT_1(int sha,int date,octet *CLIENT_ID,csprng *RNG,octet *X,int pin,octet *TOKEN,octet *SEC,octet *xID,octet *xCID,octet *PERMIT) +{ + BIG_XXX r,x; + ECP_ZZZ P,T,W; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (RNG!=NULL) + { + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + BIG_XXX_fromBytes(x,X->val); + + mhashit(sha,-1,CLIENT_ID,&H); + + ECP_ZZZ_mapit(&P,&H); + + if (!ECP_ZZZ_fromOctet(&T,TOKEN)) res=MPIN_INVALID_POINT; + + if (res==0) + { + pin%=MAXPIN; + + ECP_ZZZ_copy(&W,&P); // W=H(ID) + ECP_ZZZ_pinmul(&W,pin,PBLEN); // W=alpha.H(ID) + ECP_ZZZ_add(&T,&W); // T=Token+alpha.H(ID) = s.H(ID) + + if (date) + { + if (PERMIT!=NULL) + { + if (!ECP_ZZZ_fromOctet(&W,PERMIT)) res=MPIN_INVALID_POINT; + ECP_ZZZ_add(&T,&W); // SEC=s.H(ID)+s.H(T|ID) + } + mhashit(sha,date,&H,&H); + + ECP_ZZZ_mapit(&W,&H); + if (xID!=NULL) + { + PAIR_ZZZ_G1mul(&P,x); // P=x.H(ID) + ECP_ZZZ_toOctet(xID,&P,false); // xID + PAIR_ZZZ_G1mul(&W,x); // W=x.H(T|ID) + ECP_ZZZ_add(&P,&W); + } + else + { + ECP_ZZZ_add(&P,&W); + PAIR_ZZZ_G1mul(&P,x); + } + if (xCID!=NULL) ECP_ZZZ_toOctet(xCID,&P,false); // U + } + else + { + if (xID!=NULL) + { + PAIR_ZZZ_G1mul(&P,x); // P=x.H(ID) + ECP_ZZZ_toOctet(xID,&P,false); // xID + } + } + } + + if (res==0) + { + ECP_ZZZ_toOctet(SEC,&T,false); // V + } + return res; +} + +/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */ +int MPIN_ZZZ_GET_SERVER_SECRET(octet *S,octet *SST) +{ + BIG_XXX r,s; + ECP2_ZZZ Q; + int res=0; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + + ECP2_ZZZ_generator(&Q); + + if (res==0) + { + + BIG_XXX_fromBytes(s,S->val); + PAIR_ZZZ_G2mul(&Q,s); + ECP2_ZZZ_toOctet(SST,&Q); + } + + return res; +} + + +/* Time Permit CTT=s*H(date|H(CID)) where s is master secret */ +int MPIN_ZZZ_GET_CLIENT_PERMIT(int sha,int date,octet *S,octet *CID,octet *CTT) +{ + BIG_XXX s; + ECP_ZZZ P; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + mhashit(sha,date,CID,&H); + + ECP_ZZZ_mapit(&P,&H); + + BIG_XXX_fromBytes(s,S->val); + + PAIR_ZZZ_G1mul(&P,s); + ECP_ZZZ_toOctet(CTT,&P,false); + return 0; +} + +// if date=0 only use HID, set HCID=NULL +// if date and PE, use HID and HCID + +/* Outputs H(CID) and H(CID)+H(T|H(CID)) for time permits. If no time permits set HTID=NULL */ +void MPIN_ZZZ_SERVER_1(int sha,int date,octet *CID,octet *HID,octet *HTID) +{ + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + ECP_ZZZ P,R; + +#ifdef USE_ANONYMOUS + ECP_ZZZ_mapit(&P,CID); +#else + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&P,&H); +#endif + + ECP_ZZZ_toOctet(HID,&P,false); // new + + if (date) + { +#ifdef USE_ANONYMOUS + mhashit(sha,date,CID,&H); +#else + mhashit(sha,date,&H,&H); +#endif + ECP_ZZZ_mapit(&R,&H); + ECP_ZZZ_add(&P,&R); + ECP_ZZZ_toOctet(HTID,&P,false); + } +} + +/* Implement M-Pin on server side */ +int MPIN_ZZZ_SERVER_2(int date,octet *HID,octet *HTID,octet *Y,octet *SST,octet *xID,octet *xCID,octet *mSEC,octet *E,octet *F,octet *Pa) +{ + BIG_XXX px,py,y; + FP12_YYY g; + ECP2_ZZZ Q,sQ; + ECP_ZZZ P,R; + int res=0; + + ECP2_ZZZ_generator(&Q); + + // key-escrow less scheme: use Pa instead of Q in pairing computation + // Q left for backward compatiblity + if (Pa!=NULL) + { + if (!ECP2_ZZZ_fromOctet(&Q, Pa)) res=MPIN_INVALID_POINT; + } + + if (res==0) + { + if (!ECP2_ZZZ_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT; + } + + if (res==0) + { + if (date) + { + if (!ECP_ZZZ_fromOctet(&R,xCID)) res=MPIN_INVALID_POINT; + } + else + { + if (!ECP_ZZZ_fromOctet(&R,xID)) res=MPIN_INVALID_POINT; + } + } + if (res==0) + { + BIG_XXX_fromBytes(y,Y->val); + if (date) + { + if (!ECP_ZZZ_fromOctet(&P,HTID)) res=MPIN_INVALID_POINT; + } + else + { + if (!ECP_ZZZ_fromOctet(&P,HID)) res=MPIN_INVALID_POINT; + } + } + if (res==0) + { + PAIR_ZZZ_G1mul(&P,y); // y(A+AT) + ECP_ZZZ_add(&P,&R); // x(A+AT)+y(A+T) + if (!ECP_ZZZ_fromOctet(&R,mSEC)) res=MPIN_INVALID_POINT; // V + } + if (res==0) + { + + PAIR_ZZZ_double_ate(&g,&Q,&R,&sQ,&P); + PAIR_ZZZ_fexp(&g); + + if (!FP12_YYY_isunity(&g)) + { + if (HID!=NULL && xID!=NULL && E!=NULL && F !=NULL) + { + /* xID is set to NULL if there is no way to calculate PIN error */ + FP12_YYY_toOctet(E,&g); + + /* Note error is in the PIN, not in the time permit! Hence the need to exclude Time Permit from this check */ + + if (date) + { + if (!ECP_ZZZ_fromOctet(&P,HID)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&R,xID)) res=MPIN_INVALID_POINT; // U + + if (res==0) + { + PAIR_ZZZ_G1mul(&P,y); // yA + ECP_ZZZ_add(&P,&R); // yA+xA + } + } + if (res==0) + { + PAIR_ZZZ_ate(&g,&Q,&P); + PAIR_ZZZ_fexp(&g); + FP12_YYY_toOctet(F,&g); + } + } + res=MPIN_BAD_PIN; + } + } + + return res; +} + +#if MAXPIN==10000 +#define MR_TS 10 /* 2^10/10 approx = sqrt(MAXPIN) */ +#define TRAP 200 /* 2*sqrt(MAXPIN) */ +#endif + +#if MAXPIN==1000000 +#define MR_TS 14 +#define TRAP 2000 +#endif + +/* Pollards kangaroos used to return PIN error */ +int MPIN_ZZZ_KANGAROO(octet *E,octet *F) +{ + int i,j,m,s,dn,dm,steps; + int distance[MR_TS]; + FP12_YYY ge,gf,t,table[MR_TS]; + int res=0; + // BIG_XXX w; + + FP12_YYY_fromOctet(&ge,E); + FP12_YYY_fromOctet(&gf,F); + + FP12_YYY_copy(&t,&gf); + + for (s=1,m=0; m<MR_TS; m++) + { + distance[m]=s; + FP12_YYY_copy(&table[m],&t); + s*=2; + FP12_YYY_usqr(&t,&t); + FP12_YYY_reduce(&t); + } + + FP12_YYY_one(&t); + + for (dn=0,j=0; j<TRAP; j++) + { + i=t.a.a.a.g[0]%MR_TS; + + FP12_YYY_mul(&t,&table[i]); + FP12_YYY_reduce(&t); + dn+=distance[i]; + } + + FP12_YYY_conj(&gf,&t); + steps=0; + dm=0; + while (dm-dn<MAXPIN) + { + steps++; + if (steps>4*TRAP) break; + i=ge.a.a.a.g[0]%MR_TS; + + FP12_YYY_mul(&ge,&table[i]); + FP12_YYY_reduce(&ge); + dm+=distance[i]; + if (FP12_YYY_equals(&ge,&t)) + { + res=dm-dn; + break; + } + if (FP12_YYY_equals(&ge,&gf)) + { + res=dn-dm; + break; + } + } + if (steps>4*TRAP || dm-dn>=MAXPIN) + { + res=0; /* Trap Failed - probable invalid token */ + } + + return res; +} + +/* Functions to support M-Pin Full */ + +int MPIN_ZZZ_PRECOMPUTE(octet *TOKEN,octet *CID,octet *CP,octet *G1,octet *G2) +{ + ECP_ZZZ P,T; + ECP2_ZZZ Q; + FP12_YYY g; + int res=0; + + if (!ECP_ZZZ_fromOctet(&T,TOKEN)) res=MPIN_INVALID_POINT; + + if (res==0) + { + ECP_ZZZ_mapit(&P,CID); + if (CP!=NULL) + { + if (!ECP2_ZZZ_fromOctet(&Q,CP)) res=MPIN_INVALID_POINT; + } + else + { + ECP2_ZZZ_generator(&Q); + } + } + if (res==0) + { + PAIR_ZZZ_ate(&g,&Q,&T); + PAIR_ZZZ_fexp(&g); + + FP12_YYY_toOctet(G1,&g); + if (G2!=NULL) + { + PAIR_ZZZ_ate(&g,&Q,&P); + PAIR_ZZZ_fexp(&g); + FP12_YYY_toOctet(G2,&g); + } + } + return res; +} + +/* calculate common key on client side */ +/* wCID = w.(A+AT) */ +int MPIN_ZZZ_CLIENT_KEY(int sha,octet *G1,octet *G2,int pin,octet *R,octet *X,octet *H,octet *wCID,octet *CK) +{ + FP12_YYY g1,g2; + FP4_YYY c; + ECP_ZZZ W; + int res=0; + BIG_XXX r,z,x,h; + + FP12_YYY_fromOctet(&g1,G1); + FP12_YYY_fromOctet(&g2,G2); + BIG_XXX_fromBytes(z,R->val); + BIG_XXX_fromBytes(x,X->val); + BIG_XXX_fromBytes(h,H->val); + + if (!ECP_ZZZ_fromOctet(&W,wCID)) res=MPIN_INVALID_POINT; + + if (res==0) + { + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_add(z,z,h); // new + BIG_XXX_mod(z,r); + + FP12_YYY_pinpow(&g2,pin,PBLEN); + FP12_YYY_mul(&g1,&g2); + + PAIR_ZZZ_G1mul(&W,x); + + FP12_YYY_compow(&c,&g1,z,r); + + mpin_hash(sha,&c,&W,CK); + } + return res; +} + +/* calculate common key on server side */ +/* Z=r.A - no time permits involved */ + +int MPIN_ZZZ_SERVER_KEY(int sha,octet *Z,octet *SST,octet *W,octet *H,octet *HID,octet *xID,octet *xCID,octet *SK) +{ + int res=0; + FP12_YYY g; + FP4_YYY c; + ECP_ZZZ R,U,A; + ECP2_ZZZ sQ; + BIG_XXX w,h; + + if (!ECP2_ZZZ_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&R,Z)) res=MPIN_INVALID_POINT; + + + if (!ECP_ZZZ_fromOctet(&A,HID)) res=MPIN_INVALID_POINT; + + // new + if (xCID!=NULL) + { + if (!ECP_ZZZ_fromOctet(&U,xCID)) res=MPIN_INVALID_POINT; + } + else + { + if (!ECP_ZZZ_fromOctet(&U,xID)) res=MPIN_INVALID_POINT; + } + BIG_XXX_fromBytes(w,W->val); + BIG_XXX_fromBytes(h,H->val); + + + PAIR_ZZZ_ate(&g,&sQ,&A); + PAIR_ZZZ_fexp(&g); + + if (res==0) + { + PAIR_ZZZ_G1mul(&A,h); + ECP_ZZZ_add(&R,&A); // new + PAIR_ZZZ_ate(&g,&sQ,&R); + PAIR_ZZZ_fexp(&g); + PAIR_ZZZ_G1mul(&U,w); + FP12_YYY_trace(&c,&g); + mpin_hash(sha,&c,&U,SK); + } + return res; +} + +/* Generate Y = H(TimeValue, xCID/xID) */ +void MPIN_ZZZ_GET_Y(int sha,int TimeValue,octet *xCID,octet *Y) +{ + BIG_XXX q,y; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + mhashit(sha,TimeValue,xCID,&H); + BIG_XXX_fromBytes(y,H.val); + BIG_XXX_rcopy(q,CURVE_Order_ZZZ); + BIG_XXX_mod(y,q); + BIG_XXX_toBytes(Y->val,y); + Y->len=PGS_ZZZ; +} + +/* One pass MPIN Client */ +int MPIN_ZZZ_CLIENT(int sha,int date,octet *ID,csprng *RNG,octet *X,int pin,octet *TOKEN,octet *V,octet *U,octet *UT,octet *TP,octet *MESSAGE,int TimeValue,octet *Y) +{ + int rtn=0; + char m[M_SIZE_ZZZ]; + octet M= {0,sizeof(m),m}; + + octet *pID; + if (date == 0) + pID = U; + else + pID = UT; + + rtn = MPIN_ZZZ_CLIENT_1(sha,date,ID,RNG,X,pin,TOKEN,V,U,UT,TP); + if (rtn != 0) + return rtn; + + OCT_joctet(&M,pID); + if (MESSAGE!=NULL) + { + OCT_joctet(&M,MESSAGE); + } + + MPIN_ZZZ_GET_Y(sha,TimeValue,&M,Y); + + rtn = MPIN_ZZZ_CLIENT_2(X,Y,V); + if (rtn != 0) + return rtn; + + return 0; +} + +/* One pass MPIN Server */ +int MPIN_ZZZ_SERVER(int sha,int date,octet *HID,octet *HTID,octet *Y,octet *sQ,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *ID,octet *MESSAGE,int TimeValue, octet *Pa) +{ + int rtn=0; + char m[M_SIZE_ZZZ]; + octet M= {0,sizeof(m),m}; + + octet *pU; + if (date == 0) + pU = U; + else + pU = UT; + + MPIN_ZZZ_SERVER_1(sha,date,ID,HID,HTID); + + OCT_joctet(&M,pU); + if (MESSAGE!=NULL) + { + OCT_joctet(&M,MESSAGE); + } + + MPIN_ZZZ_GET_Y(sha,TimeValue,&M,Y); + + rtn = MPIN_ZZZ_SERVER_2(date,HID,HTID,Y,sQ,U,UT,V,E,F,Pa); + if (rtn != 0) + return rtn; + + return 0; +} + +int MPIN_ZZZ_GET_DVS_KEYPAIR(csprng *R,octet *Z,octet *Pa) +{ + BIG_XXX z,r; + ECP2_ZZZ Q; + int res=0; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + + if (R!=NULL) + { + BIG_XXX_randomnum(z,r,R); + Z->len=MODBYTES_XXX; + BIG_XXX_toBytes(Z->val,z); + } + else + BIG_XXX_fromBytes(z,Z->val); + + BIG_XXX_invmodp(z,z,r); + + ECP2_ZZZ_generator(&Q); + + if (res==0) + { + PAIR_ZZZ_G2mul(&Q,z); + ECP2_ZZZ_toOctet(Pa,&Q); + } + + return res; +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version3/c/mpin.h ---------------------------------------------------------------------- diff --git a/version3/c/mpin.h b/version3/c/mpin.h new file mode 100644 index 0000000..98c853c --- /dev/null +++ b/version3/c/mpin.h @@ -0,0 +1,345 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/** + * @file mpin.h + * @author Mike Scott + * @brief M-Pin Header file + * + * + */ + +#ifndef MPIN_ZZZ_H +#define MPIN_ZZZ_H + +#include "pair_ZZZ.h" +#include "pbc_support.h" + +/* Field size is assumed to be greater than or equal to group size */ + +#define PGS_ZZZ MODBYTES_XXX /**< MPIN Group Size */ +#define PFS_ZZZ MODBYTES_XXX /**< MPIN Field Size */ +//#define PAS_ZZZ 16 /**< MPIN Symmetric Key Size */ + +#define MPIN_OK 0 /**< Function completed without error */ +#define MPIN_INVALID_POINT -14 /**< Point is NOT on the curve */ +#define MPIN_BAD_PIN -19 /**< Bad PIN number entered */ + +#define MPIN_PAS 16 /**< MPIN Symmetric Key Size */ +#define MAXPIN 10000 /**< max PIN */ +#define PBLEN 14 /**< max length of PIN in bits */ + +//#define HASH_TYPE_MPIN_ZZZ SHA256 /**< Choose Hash function */ + +#define MESSAGE_SIZE 256 /**< Signature message size */ +#define M_SIZE_ZZZ (MESSAGE_SIZE+2*PFS_ZZZ+1) /**< Signature message size and G1 size */ + +/* MPIN support functions */ + +/* MPIN primitives */ + + +/** @brief Generate Y=H(s,O), where s is epoch time, O is an octet, and H(.) is a hash function + * + @param h is the hash type + @param t is epoch time in seconds + @param O is an input octet + @param Y is the output octet +*/ +void MPIN_ZZZ_GET_Y(int h,int t,octet *O,octet *Y); + +/** @brief Extract a PIN number from a client secret + * + @param h is the hash type + @param ID is the input client identity + @param factor is an input factor + @param facbits is the number of bits in the factor + @param CS is the client secret from which the factor is to be extracted + @return 0 or an error code + */ +int MPIN_ZZZ_EXTRACT_FACTOR(int h,octet *ID,int factor,int facbits,octet *CS); + +/** @brief Extract a PIN number from a client secret + * + @param h is the hash type + @param ID is the input client identity + @param factor is an input factor + @param facbits is the number of bits in the factor + @param CS is the client secret to which the factor is to be added + @return 0 or an error code + */ +int MPIN_ZZZ_RESTORE_FACTOR(int h,octet *ID,int factor,int facbits,octet *CS); + + +/** @brief Extract a PIN number from a client secret + * + @param h is the hash type + @param ID is the input client identity + @param pin is an input PIN number + @param CS is the client secret from which the PIN is to be extracted + @return 0 or an error code + */ +int MPIN_ZZZ_EXTRACT_PIN(int h,octet *ID,int pin,octet *CS); + + + +/** @brief Perform client side of the one-pass version of the M-Pin protocol + * + If Time Permits are disabled, set d = 0, and UT is not generated and can be set to NULL. + If Time Permits are enabled, and PIN error detection is OFF, U is not generated and can be set to NULL. + If Time Permits are enabled, and PIN error detection is ON, U and UT are both generated. + @param h is the hash type + @param d is input date, in days since the epoch. Set to 0 if Time permits disabled + @param ID is the input client identity + @param R is a pointer to a cryptographically secure random number generator + @param x an output internally randomly generated if R!=NULL, otherwise must be provided as an input + @param pin is the input PIN number + @param T is the input M-Pin token (the client secret with PIN portion removed) + @param V is output = -(x+y)(CS+TP), where CS is the reconstructed client secret, and TP is the time permit + @param U is output = x.H(ID) + @param UT is output = x.(H(ID)+H(d|H(ID))) + @param TP is the input time permit + @param MESSAGE is the message to be signed + @param t is input epoch time in seconds - a timestamp + @param y is output H(t|U) or H(t|UT) if Time Permits enabled + @return 0 or an error code + */ +int MPIN_ZZZ_CLIENT(int h,int d,octet *ID,csprng *R,octet *x,int pin,octet *T,octet *V,octet *U,octet *UT,octet *TP, octet* MESSAGE, int t, octet *y); +/** @brief Perform first pass of the client side of the 3-pass version of the M-Pin protocol + * + If Time Permits are disabled, set d = 0, and UT is not generated and can be set to NULL. + If Time Permits are enabled, and PIN error detection is OFF, U is not generated and can be set to NULL. + If Time Permits are enabled, and PIN error detection is ON, U and UT are both generated. + @param h is the hash type + @param d is input date, in days since the epoch. Set to 0 if Time permits disabled + @param ID is the input client identity + @param R is a pointer to a cryptographically secure random number generator + @param x an output internally randomly generated if R!=NULL, otherwise must be provided as an input + @param pin is the input PIN number + @param T is the input M-Pin token (the client secret with PIN portion removed) + @param S is output = CS+TP, where CS=is the reconstructed client secret, and TP is the time permit + @param U is output = x.H(ID) + @param UT is output = x.(H(ID)+H(d|H(ID))) + @param TP is the input time permit + @return 0 or an error code + */ +int MPIN_ZZZ_CLIENT_1(int h,int d,octet *ID,csprng *R,octet *x,int pin,octet *T,octet *S,octet *U,octet *UT,octet *TP); +/** @brief Generate a random group element + * + @param R is a pointer to a cryptographically secure random number generator + @param S is the output random octet + @return 0 or an error code + */ +int MPIN_ZZZ_RANDOM_GENERATE(csprng *R,octet *S); +/** @brief Perform second pass of the client side of the 3-pass version of the M-Pin protocol + * + @param x an input, a locally generated random number + @param y an input random challenge from the server + @param V on output = -(x+y).V + @return 0 or an error code + */ +int MPIN_ZZZ_CLIENT_2(octet *x,octet *y,octet *V); +/** @brief Perform server side of the one-pass version of the M-Pin protocol + * + If Time Permits are disabled, set d = 0, and UT and HTID are not generated and can be set to NULL. + If Time Permits are enabled, and PIN error detection is OFF, U and HID are not needed and can be set to NULL. + If Time Permits are enabled, and PIN error detection is ON, U, UT, HID and HTID are all required. + @param h is the hash type + @param d is input date, in days since the epoch. Set to 0 if Time permits disabled + @param HID is output H(ID), a hash of the client ID + @param HTID is output H(ID)+H(d|H(ID)) + @param y is output H(t|U) or H(t|UT) if Time Permits enabled + @param SS is the input server secret + @param U is input from the client = x.H(ID) + @param UT is input from the client= x.(H(ID)+H(d|H(ID))) + @param V is an input from the client + @param E is an output to help the Kangaroos to find the PIN error, or NULL if not required + @param F is an output to help the Kangaroos to find the PIN error, or NULL if not required + @param ID is the input claimed client identity + @param MESSAGE is the message to be signed + @param t is input epoch time in seconds - a timestamp + @param Pa is input from the client z.Q or NULL if the key-escrow less scheme is not used + @return 0 or an error code + */ +int MPIN_ZZZ_SERVER(int h,int d,octet *HID,octet *HTID,octet *y,octet *SS,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *ID,octet *MESSAGE, int t, octet *Pa); +/** @brief Perform first pass of the server side of the 3-pass version of the M-Pin protocol + * + @param h is the hash type + @param d is input date, in days since the epoch. Set to 0 if Time permits disabled + @param ID is the input claimed client identity + @param HID is output H(ID), a hash of the client ID + @param HTID is output H(ID)+H(d|H(ID)) + @return 0 or an error code + */ +void MPIN_ZZZ_SERVER_1(int h,int d,octet *ID,octet *HID,octet *HTID); +/** @brief Perform third pass on the server side of the 3-pass version of the M-Pin protocol + * + If Time Permits are disabled, set d = 0, and UT and HTID are not needed and can be set to NULL. + If Time Permits are enabled, and PIN error detection is OFF, U and HID are not needed and can be set to NULL. + If Time Permits are enabled, and PIN error detection is ON, U, UT, HID and HTID are all required. + @param d is input date, in days since the epoch. Set to 0 if Time permits disabled + @param HID is input H(ID), a hash of the client ID + @param HTID is input H(ID)+H(d|H(ID)) + @param y is the input server's randomly generated challenge + @param SS is the input server secret + @param U is input from the client = x.H(ID) + @param UT is input from the client= x.(H(ID)+H(d|H(ID))) + @param V is an input from the client + @param E is an output to help the Kangaroos to find the PIN error, or NULL if not required + @param F is an output to help the Kangaroos to find the PIN error, or NULL if not required + @param Pa is the input public key from the client, z.Q or NULL if the client uses regular mpin + @return 0 or an error code + */ +int MPIN_ZZZ_SERVER_2(int d,octet *HID,octet *HTID,octet *y,octet *SS,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *Pa); +/** @brief Add two members from the group G1 + * + @param Q1 an input member of G1 + @param Q2 an input member of G1 + @param Q an output member of G1 = Q1+Q2 + @return 0 or an error code + */ +int MPIN_ZZZ_RECOMBINE_G1(octet *Q1,octet *Q2,octet *Q); +/** @brief Add two members from the group G2 + * + @param P1 an input member of G2 + @param P2 an input member of G2 + @param P an output member of G2 = P1+P2 + @return 0 or an error code + */ +int MPIN_ZZZ_RECOMBINE_G2(octet *P1,octet *P2,octet *P); +/** @brief Use Kangaroos to find PIN error + * + @param E a member of the group GT + @param F a member of the group GT = E^e + @return 0 if Kangaroos failed, or the PIN error e + */ +int MPIN_ZZZ_KANGAROO(octet *E,octet *F); +/** @brief Encoding of a Time Permit to make it indistinguishable from a random string + * + @param R is a pointer to a cryptographically secure random number generator + @param TP is the input time permit, obfuscated on output + @return 0 or an error code + */ +int MPIN_ZZZ_ENCODING(csprng *R,octet *TP); +/** @brief Encoding of an obfuscated Time Permit + * + @param TP is the input obfuscated time permit, restored on output + @return 0 or an error code + */ +int MPIN_ZZZ_DECODING(octet *TP); + +/** @brief Find a random multiple of a point in G1 + * + @param R is a pointer to a cryptographically secure random number generator + @param type determines type of action to be taken + @param x an output internally randomly generated if R!=NULL, otherwise must be provided as an input + @param G if type=0 a point in G1, else an octet to be mapped to G1 + @param W the output =x.G or x.M(G), where M(.) is a mapping + @return 0 or an error code + */ +int MPIN_ZZZ_GET_G1_MULTIPLE(csprng *R,int type,octet *x,octet *G,octet *W); +/** @brief Find a random multiple of a point in G1 + * + @param R is a pointer to a cryptographically secure random number generator + @param type determines type of action to betaken + @param x an output internally randomly generated if R!=NULL, otherwise must be provided as an input + @param G a point in G2 + @param W the output =x.G or (1/x).G + @return 0 or an error code + */ +int MPIN_ZZZ_GET_G2_MULTIPLE(csprng *R,int type,octet *x,octet *G,octet *W); + +/** @brief Create a client secret in G1 from a master secret and the client ID + * + @param S is an input master secret + @param ID is the input client identity + @param CS is the full client secret = s.H(ID) + @return 0 or an error code + */ +int MPIN_ZZZ_GET_CLIENT_SECRET(octet *S,octet *ID,octet *CS); +/** @brief Create a Time Permit in G1 from a master secret and the client ID + * + @param h is the hash type + @param d is input date, in days since the epoch. + @param S is an input master secret + @param ID is the input client identity + @param TP is a Time Permit for the given date = s.H(d|H(ID)) + @return 0 or an error code + */ +int MPIN_ZZZ_GET_CLIENT_PERMIT(int h,int d,octet *S,octet *ID,octet *TP); +/** @brief Create a server secret in G2 from a master secret + * + @param S is an input master secret + @param SS is the server secret = s.Q where Q is a fixed generator of G2 + @return 0 or an error code + */ +int MPIN_ZZZ_GET_SERVER_SECRET(octet *S,octet *SS); +/* int MPIN_TEST_PAIRING(octet *,octet *); */ + +/* For M-Pin Full */ +/** @brief Precompute values for use by the client side of M-Pin Full + * + @param T is the input M-Pin token (the client secret with PIN portion removed) + @param ID is the input client identity + @param CP is Public Key (or NULL) + @param g1 precomputed output + @param g2 precomputed output + @return 0 or an error code + */ +int MPIN_ZZZ_PRECOMPUTE(octet *T,octet *ID,octet *CP,octet *g1,octet *g2); +/** @brief Calculate Key on Server side for M-Pin Full + * + Uses UT internally for the key calculation, unless not available in which case U is used + @param h is the hash type + @param Z is the input Client-side Diffie-Hellman component + @param SS is the input server secret + @param w is an input random number generated by the server + @param p is an input, hash of the protocol transcript + @param I is the hashed input client ID = H(ID) + @param U is input from the client = x.H(ID) + @param UT is input from the client= x.(H(ID)+H(d|H(ID))) + @param K is the output calculated shared key + @return 0 or an error code + */ +int MPIN_ZZZ_SERVER_KEY(int h,octet *Z,octet *SS,octet *w,octet *p,octet *I,octet *U,octet *UT,octet *K); +/** @brief Calculate Key on Client side for M-Pin Full + * + @param h is the hash type + @param g1 precomputed input + @param g2 precomputed input + @param pin is the input PIN number + @param r is an input, a locally generated random number + @param x is an input, a locally generated random number + @param p is an input, hash of the protocol transcript + @param T is the input Server-side Diffie-Hellman component + @param K is the output calculated shared key + @return 0 or an error code + */ +int MPIN_ZZZ_CLIENT_KEY(int h,octet *g1,octet *g2,int pin,octet *r,octet *x,octet *p,octet *T,octet *K); + +/** @brief Generates a random public key for the client z.Q + * + @param R is a pointer to a cryptographically secure random number generator + @param Z an output internally randomly generated if R!=NULL, otherwise it must be provided as an input + @param Pa the output public key for the client + */ +int MPIN_ZZZ_GET_DVS_KEYPAIR(csprng *R,octet *Z,octet *Pa); + +#endif + http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto/blob/c25f9e5c/version3/c/mpin192.c ---------------------------------------------------------------------- diff --git a/version3/c/mpin192.c b/version3/c/mpin192.c new file mode 100644 index 0000000..92b50ee --- /dev/null +++ b/version3/c/mpin192.c @@ -0,0 +1,945 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* MPIN Functions */ + +/* Version 3.0 - supports Time Permits */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "mpin192_ZZZ.h" + +#define ROUNDUP(a,b) ((a)-1)/(b)+1 + +/* Special mpin hashing */ +static void mpin_hash(int sha,FP8_YYY *f, ECP_ZZZ *P,octet *w) +{ + int i; + BIG_XXX x,y; + char h[64]; + hash256 sha256; + hash512 sha512; + char t[10*MODBYTES_XXX]; // to hold 10 BIGs + int hlen=sha; + + + FP_YYY_redc(x,&(f->a.a.a)); + BIG_XXX_toBytes(&t[0],x); + FP_YYY_redc(x,&(f->a.a.b)); + BIG_XXX_toBytes(&t[MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->a.b.a)); + BIG_XXX_toBytes(&t[2*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->a.b.b)); + BIG_XXX_toBytes(&t[3*MODBYTES_XXX],x); + + FP_YYY_redc(x,&(f->b.a.a)); + BIG_XXX_toBytes(&t[4*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.a.b)); + BIG_XXX_toBytes(&t[5*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.b.a)); + BIG_XXX_toBytes(&t[6*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.b.b)); + BIG_XXX_toBytes(&t[7*MODBYTES_XXX],x); + + ECP_ZZZ_get(x,y,P); + BIG_XXX_toBytes(&t[8*MODBYTES_XXX],x); + BIG_XXX_toBytes(&t[9*MODBYTES_XXX],y); + + OCT_empty(w); + switch (sha) + { + case SHA256: + HASH256_init(&sha256); + for (i=0; i<10*MODBYTES_XXX; i++) HASH256_process(&sha256,t[i]); + HASH256_hash(&sha256,h); + break; + case SHA384: + HASH384_init(&sha512); + for (i=0; i<10*MODBYTES_XXX; i++) HASH384_process(&sha512,t[i]); + HASH384_hash(&sha512,h); + break; + case SHA512: + HASH512_init(&sha512); + for (i=0; i<10*MODBYTES_XXX; i++) HASH512_process(&sha512,t[i]); + HASH512_hash(&sha512,h); + break; + } + + OCT_jbytes(w,h,AESKEY_ZZZ); + for (i=0; i<hlen; i++) h[i]=0; +} + +/* these next two functions help to implement elligator squared - http://eprint.iacr.org/2014/043 */ +/* maps a random u to a point on the curve */ +static void map(ECP_ZZZ *P,BIG_XXX u,int cb) +{ + BIG_XXX x,q; + + BIG_XXX_rcopy(q,Modulus_YYY); + BIG_XXX_copy(x,u); + BIG_XXX_mod(x,q); + + while (!ECP_ZZZ_setx(P,x,cb)) + { + BIG_XXX_inc(x,1); BIG_XXX_norm(x); + } +} + +/* returns u derived from P. Random value in range 1 to return value should then be added to u */ +static int unmap(BIG_XXX u,int *cb,ECP_ZZZ *P) +{ + int s,r=0; + BIG_XXX x; + + s=ECP_ZZZ_get(x,x,P); + BIG_XXX_copy(u,x); + do + { + BIG_XXX_dec(u,1); BIG_XXX_norm(u); + r++; + } + while (!ECP_ZZZ_setx(P,u,s)); + ECP_ZZZ_setx(P,x,s); + + *cb=s; + + return r; +} + +/* these next two functions implement elligator squared - http://eprint.iacr.org/2014/043 */ +/* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} */ +/* Note that u and v are indistinguisible from random strings */ +int MPIN_ZZZ_ENCODING(csprng *RNG,octet *E) +{ + int rn,m,su,sv,res=0; + + BIG_XXX q,u,v; + ECP_ZZZ P,W; + + if (!ECP_ZZZ_fromOctet(&P,E)) res=MPIN_INVALID_POINT; + if (res==0) + { + BIG_XXX_rcopy(q,Modulus_YYY); + + BIG_XXX_randomnum(u,q,RNG); + + su=RAND_byte(RNG); + if (su<0) su=-su; + su%=2; + map(&W,u,su); + ECP_ZZZ_sub(&P,&W); + + rn=unmap(v,&sv,&P); + m=RAND_byte(RNG); + if (m<0) m=-m; + m%=rn; + BIG_XXX_inc(v,m+1); + E->val[0]=su+2*sv; + BIG_XXX_toBytes(&(E->val[1]),u); + BIG_XXX_toBytes(&(E->val[PFS_ZZZ+1]),v); + } + return res; +} + +int MPIN_ZZZ_DECODING(octet *D) +{ + int su,sv; + BIG_XXX u,v; + ECP_ZZZ P,W; + int res=0; + + if ((D->val[0]&0x04)!=0) res=MPIN_INVALID_POINT; + if (res==0) + { + + BIG_XXX_fromBytes(u,&(D->val[1])); + BIG_XXX_fromBytes(v,&(D->val[PFS_ZZZ+1])); + + su=D->val[0]&1; + sv=(D->val[0]>>1)&1; + map(&W,u,su); + map(&P,v,sv); + ECP_ZZZ_add(&P,&W); + ECP_ZZZ_toOctet(D,&P,false); + } + + return res; +} + +/* R=R1+R2 in group G1 */ +int MPIN_ZZZ_RECOMBINE_G1(octet *R1,octet *R2,octet *R) +{ + ECP_ZZZ P,T; + int res=0; + if (res==0) + { + if (!ECP_ZZZ_fromOctet(&P,R1)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&T,R2)) res=MPIN_INVALID_POINT; + } + if (res==0) + { + ECP_ZZZ_add(&P,&T); + ECP_ZZZ_toOctet(R,&P,false); + } + return res; +} + +/* W=W1+W2 in group G2 */ +int MPIN_ZZZ_RECOMBINE_G2(octet *W1,octet *W2,octet *W) +{ + ECP4_ZZZ Q,T; + int res=0; + if (!ECP4_ZZZ_fromOctet(&Q,W1)) res=MPIN_INVALID_POINT; + if (!ECP4_ZZZ_fromOctet(&T,W2)) res=MPIN_INVALID_POINT; + if (res==0) + { + ECP4_ZZZ_add(&Q,&T); + ECP4_ZZZ_toOctet(W,&Q); + } + return res; +} + +/* create random secret S */ +int MPIN_ZZZ_RANDOM_GENERATE(csprng *RNG,octet* S) +{ + BIG_XXX r,s; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_randomnum(s,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(s,2*AES_S); +#endif + BIG_XXX_toBytes(S->val,s); + S->len=MODBYTES_XXX; + return 0; +} + +/* Extract PIN from TOKEN for identity CID */ +int MPIN_ZZZ_EXTRACT_PIN(int sha,octet *CID,int pin,octet *TOKEN) +{ + pin%=MAXPIN; + return MPIN_ZZZ_EXTRACT_FACTOR(sha,CID,pin,PBLEN,TOKEN); +} + +/* Extract a factor < 32 bits for identity CID */ +int MPIN_ZZZ_EXTRACT_FACTOR(int sha,octet *CID,int factor,int facbits,octet *TOKEN) +{ + ECP_ZZZ P,R; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + if (!ECP_ZZZ_fromOctet(&P,TOKEN)) res=MPIN_INVALID_POINT; + if (res==0) + { + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&R,&H); + + ECP_ZZZ_pinmul(&R,factor,facbits); + ECP_ZZZ_sub(&P,&R); + + ECP_ZZZ_toOctet(TOKEN,&P,false); + } + return res; +} + +/* Extract a factor < 32 bits for identity CID */ +int MPIN_ZZZ_RESTORE_FACTOR(int sha,octet *CID,int factor,int facbits,octet *TOKEN) +{ + ECP_ZZZ P,R; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + if (!ECP_ZZZ_fromOctet(&P,TOKEN)) res=MPIN_INVALID_POINT; + if (res==0) + { + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&R,&H); + + ECP_ZZZ_pinmul(&R,factor,facbits); + ECP_ZZZ_add(&P,&R); + + ECP_ZZZ_toOctet(TOKEN,&P,false); + } + return res; +} + +/* Implement step 2 on client side of MPin protocol - SEC=-(x+y)*SEC */ +int MPIN_ZZZ_CLIENT_2(octet *X,octet *Y,octet *SEC) +{ + BIG_XXX px,py,r; + ECP_ZZZ P; + int res=0; + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (!ECP_ZZZ_fromOctet(&P,SEC)) res=MPIN_INVALID_POINT; + if (res==0) + { + BIG_XXX_fromBytes(px,X->val); + BIG_XXX_fromBytes(py,Y->val); + BIG_XXX_add(px,px,py); + BIG_XXX_mod(px,r); + PAIR_ZZZ_G1mul(&P,px); + ECP_ZZZ_neg(&P); + ECP_ZZZ_toOctet(SEC,&P,false); + } + return res; +} + +/* + W=x*H(G); + if RNG == NULL then X is passed in + if RNG != NULL the X is passed out + if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve +*/ + +int MPIN_ZZZ_GET_G1_MULTIPLE(csprng *RNG,int type,octet *X,octet *G,octet *W) +{ + ECP_ZZZ P; + BIG_XXX r,x; + int res=0; + if (RNG!=NULL) + { + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + BIG_XXX_fromBytes(x,X->val); + + if (type==0) + { + if (!ECP_ZZZ_fromOctet(&P,G)) res=MPIN_INVALID_POINT; + } + else + { + ECP_ZZZ_mapit(&P,G); + } + + if (res==0) + { + PAIR_ZZZ_G1mul(&P,x); + ECP_ZZZ_toOctet(W,&P,false); + } + return res; +} + +/* + if RNG == NULL then X is passed in + if RNG != NULL the X is passed out + W=x*G where G is point on the curve + if type==1 W=(x^-1)G +*/ + +int MPIN_ZZZ_GET_G2_MULTIPLE(csprng *RNG,int type,octet *X,octet *G,octet *W) +{ + ECP4_ZZZ P; + BIG_XXX r,x; + int res=0; + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (RNG!=NULL) + { + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + { + BIG_XXX_fromBytes(x,X->val); + if (type==1) BIG_XXX_invmodp(x,x,r); + } + + if (!ECP4_ZZZ_fromOctet(&P,G)) res=MPIN_INVALID_POINT; + + if (res==0) + { + PAIR_ZZZ_G2mul(&P,x); + ECP4_ZZZ_toOctet(W,&P); + } + return res; +} + + + +/* Client secret CST=s*H(CID) where CID is client ID and s is master secret */ +/* CID is hashed externally */ +int MPIN_ZZZ_GET_CLIENT_SECRET(octet *S,octet *CID,octet *CST) +{ + return MPIN_ZZZ_GET_G1_MULTIPLE(NULL,1,S,CID,CST); +} + +/* Implement step 1 on client side of MPin protocol */ +int MPIN_ZZZ_CLIENT_1(int sha,int date,octet *CLIENT_ID,csprng *RNG,octet *X,int pin,octet *TOKEN,octet *SEC,octet *xID,octet *xCID,octet *PERMIT) +{ + BIG_XXX r,x; + ECP_ZZZ P,T,W; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (RNG!=NULL) + { + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + BIG_XXX_fromBytes(x,X->val); + + mhashit(sha,-1,CLIENT_ID,&H); + + ECP_ZZZ_mapit(&P,&H); + + if (!ECP_ZZZ_fromOctet(&T,TOKEN)) res=MPIN_INVALID_POINT; + + if (res==0) + { + pin%=MAXPIN; + + ECP_ZZZ_copy(&W,&P); // W=H(ID) + ECP_ZZZ_pinmul(&W,pin,PBLEN); // W=alpha.H(ID) + ECP_ZZZ_add(&T,&W); // T=Token+alpha.H(ID) = s.H(ID) + + if (date) + { + if (PERMIT!=NULL) + { + if (!ECP_ZZZ_fromOctet(&W,PERMIT)) res=MPIN_INVALID_POINT; + ECP_ZZZ_add(&T,&W); // SEC=s.H(ID)+s.H(T|ID) + } + mhashit(sha,date,&H,&H); + + ECP_ZZZ_mapit(&W,&H); + if (xID!=NULL) + { + PAIR_ZZZ_G1mul(&P,x); // P=x.H(ID) + ECP_ZZZ_toOctet(xID,&P,false); // xID + PAIR_ZZZ_G1mul(&W,x); // W=x.H(T|ID) + ECP_ZZZ_add(&P,&W); + } + else + { + ECP_ZZZ_add(&P,&W); + PAIR_ZZZ_G1mul(&P,x); + } + if (xCID!=NULL) ECP_ZZZ_toOctet(xCID,&P,false); // U + } + else + { + if (xID!=NULL) + { + PAIR_ZZZ_G1mul(&P,x); // P=x.H(ID) + ECP_ZZZ_toOctet(xID,&P,false); // xID + } + } + } + + if (res==0) + { + ECP_ZZZ_toOctet(SEC,&T,false); // V + } + return res; +} + +/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */ +int MPIN_ZZZ_GET_SERVER_SECRET(octet *S,octet *SST) +{ + BIG_XXX r,s; + ECP4_ZZZ Q; + int res=0; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + + ECP4_ZZZ_generator(&Q); + + if (res==0) + { + BIG_XXX_fromBytes(s,S->val); + PAIR_ZZZ_G2mul(&Q,s); + ECP4_ZZZ_toOctet(SST,&Q); + } + + return res; +} + + +/* Time Permit CTT=s*H(date|H(CID)) where s is master secret */ +int MPIN_ZZZ_GET_CLIENT_PERMIT(int sha,int date,octet *S,octet *CID,octet *CTT) +{ + BIG_XXX s; + ECP_ZZZ P; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + mhashit(sha,date,CID,&H); + + ECP_ZZZ_mapit(&P,&H); + + BIG_XXX_fromBytes(s,S->val); + + PAIR_ZZZ_G1mul(&P,s); + + ECP_ZZZ_toOctet(CTT,&P,false); + return 0; +} + +// if date=0 only use HID, set HCID=NULL +// if date and PE, use HID and HCID + +/* Outputs H(CID) and H(CID)+H(T|H(CID)) for time permits. If no time permits set HTID=NULL */ +void MPIN_ZZZ_SERVER_1(int sha,int date,octet *CID,octet *HID,octet *HTID) +{ + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + ECP_ZZZ P,R; + BIG_XXX x; + +#ifdef USE_ANONYMOUS + ECP_ZZZ_mapit(&P,CID); +#else + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&P,&H); +#endif + + ECP_ZZZ_toOctet(HID,&P,false); // new + + if (date) + { +#ifdef USE_ANONYMOUS + mhashit(sha,date,CID,&H); +#else + mhashit(sha,date,&H,&H); +#endif + ECP_ZZZ_mapit(&R,&H); + ECP_ZZZ_add(&P,&R); + ECP_ZZZ_toOctet(HTID,&P,false); + } +} + +/* Implement M-Pin on server side */ +int MPIN_ZZZ_SERVER_2(int date,octet *HID,octet *HTID,octet *Y,octet *SST,octet *xID,octet *xCID,octet *mSEC,octet *E,octet *F,octet *Pa) +{ + BIG_XXX px,py,y; + FP24_YYY g; + ECP4_ZZZ Q,sQ; + ECP_ZZZ P,R; + int res=0; + + ECP4_ZZZ_generator(&Q); + + // key-escrow less scheme: use Pa instead of Q in pairing computation + // Q left for backward compatiblity + if (Pa!=NULL) + { + if (!ECP4_ZZZ_fromOctet(&Q, Pa)) res=MPIN_INVALID_POINT; + } + + + if (res==0) + { + if (!ECP4_ZZZ_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT; + } + + if (res==0) + { + if (date) + { + if (!ECP_ZZZ_fromOctet(&R,xCID)) res=MPIN_INVALID_POINT; + } + else + { + if (!ECP_ZZZ_fromOctet(&R,xID)) res=MPIN_INVALID_POINT; + } + } + if (res==0) + { + BIG_XXX_fromBytes(y,Y->val); + if (date) + { + if (!ECP_ZZZ_fromOctet(&P,HTID)) res=MPIN_INVALID_POINT; + } + else + { + if (!ECP_ZZZ_fromOctet(&P,HID)) res=MPIN_INVALID_POINT; + } + } + if (res==0) + { + PAIR_ZZZ_G1mul(&P,y); // y(A+AT) + ECP_ZZZ_add(&P,&R); // x(A+AT)+y(A+T) + if (!ECP_ZZZ_fromOctet(&R,mSEC)) res=MPIN_INVALID_POINT; // V + } + if (res==0) + { + + PAIR_ZZZ_double_ate(&g,&Q,&R,&sQ,&P); + PAIR_ZZZ_fexp(&g); + + if (!FP24_YYY_isunity(&g)) + { + if (HID!=NULL && xID!=NULL && E!=NULL && F !=NULL) + { + /* xID is set to NULL if there is no way to calculate PIN error */ + FP24_YYY_toOctet(E,&g); + + /* Note error is in the PIN, not in the time permit! Hence the need to exclude Time Permit from this check */ + + if (date) + { + if (!ECP_ZZZ_fromOctet(&P,HID)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&R,xID)) res=MPIN_INVALID_POINT; // U + + if (res==0) + { + PAIR_ZZZ_G1mul(&P,y); // yA + ECP_ZZZ_add(&P,&R); // yA+xA + } + } + if (res==0) + { + PAIR_ZZZ_ate(&g,&Q,&P); + PAIR_ZZZ_fexp(&g); + FP24_YYY_toOctet(F,&g); + } + } + res=MPIN_BAD_PIN; + } + } + + return res; +} + +#if MAXPIN==10000 +#define MR_TS 10 /* 2^10/10 approx = sqrt(MAXPIN) */ +#define TRAP 200 /* 2*sqrt(MAXPIN) */ +#endif + +#if MAXPIN==1000000 +#define MR_TS 14 +#define TRAP 2000 +#endif + +/* Pollards kangaroos used to return PIN error */ +int MPIN_ZZZ_KANGAROO(octet *E,octet *F) +{ + int i,j,m,s,dn,dm,steps; + int distance[MR_TS]; + FP24_YYY ge,gf,t,table[MR_TS]; + int res=0; + + FP24_YYY_fromOctet(&ge,E); + FP24_YYY_fromOctet(&gf,F); + + FP24_YYY_copy(&t,&gf); + + for (s=1,m=0; m<MR_TS; m++) + { + distance[m]=s; + FP24_YYY_copy(&table[m],&t); + s*=2; + FP24_YYY_usqr(&t,&t); + FP24_YYY_reduce(&t); + } + + FP24_YYY_one(&t); + + for (dn=0,j=0; j<TRAP; j++) + { + i=t.a.a.a.a.g[0]%MR_TS; + + FP24_YYY_mul(&t,&table[i]); + FP24_YYY_reduce(&t); + dn+=distance[i]; + } + + FP24_YYY_conj(&gf,&t); + steps=0; + dm=0; + while (dm-dn<MAXPIN) + { + steps++; + if (steps>4*TRAP) break; + + i=ge.a.a.a.a.g[0]%MR_TS; + + FP24_YYY_mul(&ge,&table[i]); + FP24_YYY_reduce(&ge); + dm+=distance[i]; + if (FP24_YYY_equals(&ge,&t)) + { + res=dm-dn; + break; + } + if (FP24_YYY_equals(&ge,&gf)) + { + res=dn-dm; + break; + } + } + if (steps>4*TRAP || dm-dn>=MAXPIN) + { + res=0; /* Trap Failed - probable invalid token */ + } + + return res; +} + +/* Functions to support M-Pin Full */ + +int MPIN_ZZZ_PRECOMPUTE(octet *TOKEN,octet *CID,octet *CP,octet *G1,octet *G2) +{ + ECP_ZZZ P,T; + ECP4_ZZZ Q; + FP24_YYY g; + BIG_XXX x; + int res=0; + + if (!ECP_ZZZ_fromOctet(&T,TOKEN)) res=MPIN_INVALID_POINT; + + if (res==0) + { + ECP_ZZZ_mapit(&P,CID); + if (CP!=NULL) + { + if (!ECP4_ZZZ_fromOctet(&Q,CP)) res=MPIN_INVALID_POINT; + } + else + { + ECP4_ZZZ_generator(&Q); + } + } + if (res==0) + { + PAIR_ZZZ_ate(&g,&Q,&T); + PAIR_ZZZ_fexp(&g); + + FP24_YYY_toOctet(G1,&g); + if (G2!=NULL) + { + PAIR_ZZZ_ate(&g,&Q,&P); + PAIR_ZZZ_fexp(&g); + FP24_YYY_toOctet(G2,&g); + } + } + return res; +} + +/* calculate common key on client side */ +/* wCID = w.(A+AT) */ +int MPIN_ZZZ_CLIENT_KEY(int sha,octet *G1,octet *G2,int pin,octet *R,octet *X,octet *H,octet *wCID,octet *CK) +{ + FP24_YYY g1,g2; + FP8_YYY c; + + ECP_ZZZ W; + int res=0; + BIG_XXX r,z,x,h; + + FP24_YYY_fromOctet(&g1,G1); + FP24_YYY_fromOctet(&g2,G2); + BIG_XXX_fromBytes(z,R->val); + BIG_XXX_fromBytes(x,X->val); + BIG_XXX_fromBytes(h,H->val); + + if (!ECP_ZZZ_fromOctet(&W,wCID)) res=MPIN_INVALID_POINT; + + if (res==0) + { + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_add(z,z,h); // new + BIG_XXX_mod(z,r); + + FP24_YYY_pinpow(&g2,pin,PBLEN); + FP24_YYY_mul(&g1,&g2); + + PAIR_ZZZ_G1mul(&W,x); + + FP24_YYY_compow(&c,&g1,z,r); + mpin_hash(sha,&c,&W,CK); + + } + return res; +} + +/* calculate common key on server side */ +/* Z=r.A - no time permits involved */ + +int MPIN_ZZZ_SERVER_KEY(int sha,octet *Z,octet *SST,octet *W,octet *H,octet *HID,octet *xID,octet *xCID,octet *SK) +{ + int res=0; + FP24_YYY g; + FP8_YYY c; + ECP_ZZZ R,U,A; + ECP4_ZZZ sQ; + BIG_XXX w,h; + + if (!ECP4_ZZZ_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&R,Z)) res=MPIN_INVALID_POINT; + + + if (!ECP_ZZZ_fromOctet(&A,HID)) res=MPIN_INVALID_POINT; + + // new + if (xCID!=NULL) + { + if (!ECP_ZZZ_fromOctet(&U,xCID)) res=MPIN_INVALID_POINT; + } + else + { + if (!ECP_ZZZ_fromOctet(&U,xID)) res=MPIN_INVALID_POINT; + } + BIG_XXX_fromBytes(w,W->val); + BIG_XXX_fromBytes(h,H->val); + + + PAIR_ZZZ_ate(&g,&sQ,&A); + PAIR_ZZZ_fexp(&g); + + if (res==0) + { + PAIR_ZZZ_G1mul(&A,h); + ECP_ZZZ_add(&R,&A); // new + PAIR_ZZZ_ate(&g,&sQ,&R); + PAIR_ZZZ_fexp(&g); + PAIR_ZZZ_G1mul(&U,w); + FP24_YYY_trace(&c,&g); + mpin_hash(sha,&c,&U,SK); + } + return res; +} + +/* Generate Y = H(TimeValue, xCID/xID) */ +void MPIN_ZZZ_GET_Y(int sha,int TimeValue,octet *xCID,octet *Y) +{ + BIG_XXX q,y; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + mhashit(sha,TimeValue,xCID,&H); + BIG_XXX_fromBytes(y,H.val); + BIG_XXX_rcopy(q,CURVE_Order_ZZZ); + BIG_XXX_mod(y,q); + BIG_XXX_toBytes(Y->val,y); + Y->len=PGS_ZZZ; +} + +/* One pass MPIN Client */ +int MPIN_ZZZ_CLIENT(int sha,int date,octet *ID,csprng *RNG,octet *X,int pin,octet *TOKEN,octet *V,octet *U,octet *UT,octet *TP,octet *MESSAGE,int TimeValue,octet *Y) +{ + int rtn=0; + char m[M_SIZE_ZZZ]; + octet M= {0,sizeof(m),m}; + + octet *pID; + if (date == 0) + pID = U; + else + pID = UT; + + rtn = MPIN_ZZZ_CLIENT_1(sha,date,ID,RNG,X,pin,TOKEN,V,U,UT,TP); + if (rtn != 0) + return rtn; + + OCT_joctet(&M,pID); + if (MESSAGE!=NULL) + { + OCT_joctet(&M,MESSAGE); + } + + MPIN_ZZZ_GET_Y(sha,TimeValue,&M,Y); + + rtn = MPIN_ZZZ_CLIENT_2(X,Y,V); + if (rtn != 0) + return rtn; + + return 0; +} + +/* One pass MPIN Server */ +int MPIN_ZZZ_SERVER(int sha,int date,octet *HID,octet *HTID,octet *Y,octet *sQ,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *ID,octet *MESSAGE,int TimeValue, octet *Pa) +{ + int rtn=0; + char m[M_SIZE_ZZZ]; + octet M= {0,sizeof(m),m}; + + octet *pU; + if (date == 0) + pU = U; + else + pU = UT; + + MPIN_ZZZ_SERVER_1(sha,date,ID,HID,HTID); + + OCT_joctet(&M,pU); + if (MESSAGE!=NULL) + { + OCT_joctet(&M,MESSAGE); + } + + MPIN_ZZZ_GET_Y(sha,TimeValue,&M,Y); + + rtn = MPIN_ZZZ_SERVER_2(date,HID,HTID,Y,sQ,U,UT,V,E,F,Pa); + if (rtn != 0) + return rtn; + + return 0; +} + +int MPIN_ZZZ_GET_DVS_KEYPAIR(csprng *R,octet *Z,octet *Pa) +{ + BIG_XXX z,r; + ECP4_ZZZ Q; + int res=0; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + + if (R!=NULL) + { + BIG_XXX_randomnum(z,r,R); + Z->len=MODBYTES_XXX; + BIG_XXX_toBytes(Z->val,z); + } + else + BIG_XXX_fromBytes(z,Z->val); + + BIG_XXX_invmodp(z,z,r); + + ECP4_ZZZ_generator(&Q); + + if (res==0) + { + PAIR_ZZZ_G2mul(&Q,z); + ECP4_ZZZ_toOctet(Pa,&Q); + } + + return res; +} \ No newline at end of file
