import * as CTX from 'milagro-crypto-js' ; import * as utils from '../utils' ; /**
 * Issuer
 *  Issuer in Anonymous Credential
 */ export class Issuer { sk : SecretKey ; pk : IssuerPublicKey ; AttributeName : string [ ] ; param : CryptoSuite ; constructor ( curve ) { this . param = new CryptoSuite ( curve ) ; this . sk = new SecretKey ( this . param ) ; } GenerateSk ( ) { this . sk . Rand ( ) ; return this . sk ; } GenerateKeyPair ( ) { this . sk = SecretKey . GenerateSk ( this . param ) ; this . pk = this . sk . GenerateIssuerPublicKey ( ) ; } SetAttributeSet ( AttributeName ) { this . AttributeName = AttributeName ; this . pk . GenerateAttr ( AttributeName ) ; } Sign ( Nym , attrs ) { const e = this . param . getRandBN ( ) ; const s = this . param . getRandBN ( ) ; const B = new this . param . ECP ( ) ; B . copy ( this . param . g1 ) ; B . add ( this . param . PAIR . G1mul ( this . pk . h0 , s ) ) ; B . add ( Nym ) ; for ( let i = 0 ; i < this . pk . attr . length ; i ++ ) { B . add ( this . param . PAIR . G1mul ( this . pk . h [ i ] , attrs [ i ] ) ) ; } let A = new this . param . ECP ( ) ; const tmp = new this . param . BIG ( ) ; tmp . copy ( e ) ; tmp . add ( this . sk . value ) ; tmp . invmodp ( this . param . order ) ; A = this . param . PAIR . G1mul ( B , tmp ) ; const cred = new Credential ( this . param ) ; cred . Set ( A , B , e , s , attrs ) ; return cred ; } GetPk ( ) { return IssuerPublicKey . COPY ( this . pk ) ; } GenerateNonce ( ) { const nonce = this . param . getRandBN ( ) ; return nonce ; } VerifyCredentialRequest ( CR ) { return this . pk . VerifyCredentialRequest ( CR ) ; } } /**
 * User
 *  An user in Anonymous Credential
 *  Prover and Verifier are all user.
 */ export class User { attrs : any [ ] ; private sk : SecretKey ; private Nym : any ; private Cred : Credential ; private ipk : IssuerPublicKey ; private param : CryptoSuite ; constructor ( curve ) { this . param = new CryptoSuite ( curve ) ; } GenerateSk ( ) { this . sk = SecretKey . GenerateSk ( this . param ) ; return this . sk ; } SetIpk ( ipk ) { this . ipk = IssuerPublicKey . COPY ( ipk ) ; } GenerateCrendentialRequest ( nonce ) { if ( this . ipk === undefined ) { console . log ( 'Please set ipk first.' ) ; return ; } const ipk = this . ipk ; const Nym = this . param . PAIR . G1mul ( ipk . h_sk , this . sk . value ) ; const r = this . param . getRandBN ( ) ; const t1 = this . param . PAIR . G1mul ( ipk . h_sk , r ) ; const C = this . param . hashToBN ( t1 , ipk . h_sk , Nym , nonce ) ; const S = this . param . BIG . modmul ( C , this . sk . value , this . param . order ) ; S . add ( r ) ; S . mod ( this . param . order ) ; const pi = { C , S } ; const attrs = this . param . genAttrBN ( ipk . attr ) ; this . Nym = Nym ; this . attrs = attrs ; const CR = { Nym , pi , nonce , attrs } ; return CR ; } VerifyBBSplus ( Cred ) { const wg2e = new this . param . ECP2 ( ) ; wg2e . copy ( this . ipk . w ) ; wg2e . add ( this . param . PAIR . G2mul ( this . param . g2 , Cred . sig . e ) ) ; wg2e . affine ( ) ; const A = new this . param . ECP ( ) ; A . copy ( Cred . sig . A ) ; A . affine ( ) ; let left = this . param . PAIR . ate ( wg2e , A ) ; left = this . param . PAIR . fexp ( left ) ; const B = new this . param . ECP ( ) ; B . copy ( this . param . g1 ) ; B . add ( this . param . PAIR . G1mul ( this . ipk . h0 , Cred . sig . s ) ) ; B . add ( this . Nym ) ; for ( let i = 0 ; i < Cred . attrs . length ; i ++ ) { B . add ( this . param . PAIR . G1mul ( this . ipk . h [ i ] , Cred . attrs [ i ] ) ) ; } B . affine ( ) ; let right = this . param . PAIR . ate ( this . param . g2 , B ) ; right = this . param . PAIR . fexp ( right ) ; return left . equals ( right ) ; } SetCredential ( Cred ) { this . Cred = new Credential ( this . param ) ; this . Cred . Copy ( Cred ) ; return true ; } Prove ( D ) { const ipk = this . ipk ; const Cred = this . Cred ; const r1 = this . param . getRandBN ( ) ; const A_ = this . param . PAIR . G1mul ( Cred . sig . A , r1 ) ; const r3 = new this . param . BIG ( 0 ) ; r3 . copy ( r1 ) ; r3 . invmodp ( this . param . order ) ; let _e = new this . param . BIG ( 0 ) ; _e . copy ( Cred . sig . e ) ; _e = this . param . BIG . modneg ( _e , this . param . order ) ; const _A = this . param . PAIR . G1mul ( A_ , _e ) ; _A . add ( this . param . PAIR . G1mul ( Cred . sig . B , r1 ) ) ; const r2 = this . param . getRandBN ( ) ; let _r2 = new this . param . BIG ( 0 ) ; _r2 . copy ( r2 ) ; _r2 = this . param . BIG . modneg ( _r2 , this . param . order ) ; const B_ = this . param . PAIR . G1mul ( Cred . sig . B , r1 ) ; B_ . add ( this . param . PAIR . G1mul ( ipk . h0 , _r2 ) ) ; let s_ = this . param . BIG . modmul ( r2 , r3 , this . param . order ) ; s_ = this . param . BIG . modneg ( s_ , this . param . order ) ; s_ . add ( Cred . sig . s ) ; s_ . mod ( this . param . order ) ; const r_a = [ ] ; for ( let i = 0 ; i < D . length ; i ++ ) { if ( D [ i ] === 0 ) { r_a [ i ] = this . param . getRandBN ( ) ; } else { r_a [ i ] = false ; } } const r_e = this . param . getRandBN ( ) ; const r_r2 = this . param . getRandBN ( ) ; const r_r3 = this . param . getRandBN ( ) ; const r_s_ = this . param . getRandBN ( ) ; const r_sk = this . param . getRandBN ( ) ; const E = this . param . PAIR . G1mul ( ipk . h_sk , r_sk ) ; const t1 = this . param . PAIR . G1mul ( A_ , r_e ) ; t1 . add ( this . param . PAIR . G1mul ( ipk . h0 , r_r2 ) ) ; const t2 = this . param . PAIR . G1mul ( B_ , r_r3 ) ; t2 . add ( this . param . PAIR . G1mul ( ipk . h0 , r_s_ ) ) ; t2 . add ( this . param . PAIR . G1mul ( E , new this . param . BIG ( - 1 ) ) ) ; for ( let i = 0 ; i < r_a . length ; i ++ ) { if ( r_a [ i ] !== false ) { t2 . add ( this . param . PAIR . G1mul ( ipk . h [ i ] , r_a [ i ] ) ) ; } } const c_ = this . param . hashToBN ( A_ , _A , B_ , this . Nym , t1 , t2 , this . param . g1 , ipk . h0 , ipk . h , ipk . w ) ; const nonce = this . param . getRandBN ( ) ; const c = this . param . hashToBN ( nonce , c_ , D , this . attrs ) ; const s_sk = new this . param . BIG ( 0 ) ; s_sk . copy ( r_sk ) ; s_sk . add ( this . param . BIG . modmul ( c , this . sk . value , this . param . order ) ) ; s_sk . mod ( this . param . order ) ; const s_a = [ ] ; for ( let i = 0 ; i < D . length ; i ++ ) { if ( D [ i ] === 0 ) { s_a [ i ] = new this . param . BIG ( 0 ) ; s_a [ i ] . copy ( r_a [ i ] ) ; s_a [ i ] . sub ( this . param . BIG . modmul ( c , this . attrs [ i ] , this . param . order ) ) ; s_a [ i ] . mod ( this . param . order ) ; } else { s_a [ i ] = false ; } } const s_e = new this . param . BIG ( 0 ) ; s_e . copy ( r_e ) ; s_e . sub ( this . param . BIG . modmul ( c , Cred . sig . e , this . param . order ) ) ; s_e . mod ( this . param . order ) ; const s_r2 = new this . param . BIG ( 0 ) ; s_r2 . copy ( r_r2 ) ; s_r2 . add ( this . param . BIG . modmul ( c , r2 , this . param . order ) ) ; s_r2 . mod ( this . param . order ) ; const s_r3 = new this . param . BIG ( 0 ) ; s_r3 . copy ( r_r3 ) ; s_r3 . add ( this . param . BIG . modmul ( c , r3 , this . param . order ) ) ; s_r3 . mod ( this . param . order ) ; const s_s_ = new this . param . BIG ( 0 ) ; s_s_ . copy ( r_s_ ) ; s_s_ . sub ( this . param . BIG . modmul ( c , s_ , this . param . order ) ) ; s_s_ . mod ( this . param . order ) ; const pi = { c , s_sk , s_a , s_e , s_r2 , s_r3 , s_s_ , nonce } ; const proof = { A_ , _A , B_ , Nym : this . Nym , pi } ; return proof ; } Verify ( proof , D , attrs ) { const ipk = this . ipk ; const O = new this . param . ECP ( 0 ) ; if ( proof . A_ . equals ( O ) ) { console . log ( 'A\' == O return true, verify failed.' ) ; return false ; } const A_ = new this . param . ECP ( ) ; A_ . copy ( proof . A_ ) ; const w = new this . param . ECP2 ( ) ; w . copy ( ipk . w ) ; const _A = new this . param . ECP ( ) ; _A . copy ( proof . _A ) ; const g2Dup = new this . param . ECP2 ( ) ; g2Dup . copy ( this . param . g2 ) ; A_ . affine ( ) ; w . affine ( ) ; _A . affine ( ) ; g2Dup . affine ( ) ; let left = this . param . PAIR . ate ( w , A_ ) ; let right = this . param . PAIR . ate ( g2Dup , _A ) ; left = this . param . PAIR . fexp ( left ) ; right = this . param . PAIR . fexp ( right ) ; if ( ! left . equals ( right ) ) { console . log ( 'e(A\', w) == e(_A, g2) return false, verify failed.' ) ; return false ; } _A . copy ( proof . _A ) ; const _t1 = this . param . PAIR . G1mul ( A_ , proof . pi . s_e ) ; _t1 . add ( this . param . PAIR . G1mul ( ipk . h0 , proof . pi . s_r2 ) ) ; _A . sub ( proof . B_ ) ; _t1 . add ( this . param . PAIR . G1mul ( _A , this . param . BIG . modneg ( proof . pi . c , this . param . order ) ) ) ; const _t2 = this . param . PAIR . G1mul ( proof . B_ , proof . pi . s_r3 ) ; _t2 . add ( this . param . PAIR . G1mul ( ipk . h0 , proof . pi . s_s_ ) ) ; _t2 . add ( this . param . PAIR . G1mul ( ipk . h_sk , this . param . BIG . modneg ( proof . pi . s_sk , this . param . order ) ) ) ; const sum = new this . param . ECP ( ) ; sum . copy ( this . param . g1 ) ; for ( let i = 0 ; i < D . length ; i ++ ) { if ( D [ i ] === 0 ) { _t2 . add ( this . param . PAIR . G1mul ( ipk . h [ i ] , proof . pi . s_a [ i ] ) ) ; } else { sum . add ( this . param . PAIR . G1mul ( ipk . h [ i ] , attrs [ i ] ) ) ; } } _t2 . add ( this . param . PAIR . G1mul ( sum , this . param . BIG . modneg ( proof . pi . c , this . param . order ) ) ) ; const c1 = this . param . hashToBN ( proof . A_ , proof . _A , proof . B_ , proof . Nym , _t1 , _t2 , this . param . g1 , ipk . h0 , ipk . h , ipk . w ) ; const c2 = this . param . hashToBN ( proof . pi . nonce , c1 , D , attrs ) ; if ( this . param . BIG . comp ( c2 , proof . pi . c ) !== 0 ) { console . log ( 'c == H(nonce, H(A\', _A, B\', Nym, ~t1, ~t2, g1, HRand, h1, ... , hL, w), (D, I)) return false, verify failed.' ) ; return false ; } return true ; } } /**
 * CryptoSuite
 *  contains everything in Paring Based Cryptography
 */ export class CryptoSuite { curve : string ; ctx : any ; order : any ; PAIR : any ; ECP : any ; ECP2 : any ; BIG : any ; rng : any ; g1 : any ; g2 : any ; constructor ( curve ) { this . curve = curve ; this . ctx = new CTX ( curve ) ; this . PAIR = this . ctx . PAIR ; this . ECP = this . ctx . ECP ; this . ECP2 = this . ctx . ECP2 ; this . BIG = this . ctx . BIG ; this . rng = new this . ctx . RAND ( ) ; this . g1 = this . getG1Generator ( ) ; this . g2 = this . getG2Generator ( ) ; this . order = this . getOrder ( ) ; } getG1Generator ( ) { const g1 = new this . ctx . ECP ( 0 ) ; const x = new this . ctx . BIG ( 0 ) ; const y = new this . ctx . BIG ( 0 ) ; x . rcopy ( this . ctx . ROM_CURVE . CURVE_Gx ) ; y . rcopy ( this . ctx . ROM_CURVE . CURVE_Gy ) ; g1 . setxy ( x , y ) ; return g1 ; } getG2Generator ( ) { const g2 = new this . ctx . ECP2 ( 0 ) ; const x = new this . ctx . BIG ( 0 ) ; const y = new this . ctx . BIG ( 0 ) ; const qx = new this . ctx . FP2 ( 0 ) ; const qy = new this . ctx . FP2 ( 0 ) ; x . rcopy ( this . ctx . ROM_CURVE . CURVE_Pxa ) ; y . rcopy ( this . ctx . ROM_CURVE . CURVE_Pxb ) ; qx . bset ( x , y ) ; x . rcopy ( this . ctx . ROM_CURVE . CURVE_Pya ) ; y . rcopy ( this . ctx . ROM_CURVE . CURVE_Pyb ) ; qy . bset ( x , y ) ; g2 . setxy ( qx , qy ) ; return g2 ; } getOrder ( ) { const r = new this . ctx . BIG ( 0 ) ; r . rcopy ( this . ctx . ROM_CURVE . CURVE_Order ) ; return r ; } getRandBN ( ) { const buf = utils . generateRandomArray ( 256 ) ; this . rng . clean ( ) ; this . rng . seed ( 256 , buf ) ; const r = this . BIG . randomnum ( this . order , this . rng ) ; return r ; } getRandG1 ( ) { const r = this . getRandBN ( ) ; const g = this . PAIR . G1mul ( this . g1 , r ) ; return g ; } getRandG2 ( ) { const r = this . getRandBN ( ) ; const g = this . PAIR . G2mul ( this . g2 , r ) ; return g ; } hashToBN ( ... points ) { let all = [ ] ; let tmp = [ ] ; points . forEach ( ( p ) => { if ( Array . isArray ( p ) ) { if ( typeof p [ 0 ] === 'number' ) { all = all . concat ( p ) ; tmp = [ ] ; } else { p . forEach ( ( pp ) => { pp . toBytes ( tmp ) ; all = all . concat ( tmp ) ; tmp = [ ] ; } ) ; } } else { p . toBytes ( tmp ) ; all = all . concat ( tmp ) ; tmp = [ ] ; } } ) ; const H = new this . ctx . HASH256 ( ) ; H . process_array ( all ) ; const R = H . hash ( ) ; const C = this . BIG . fromBytes ( R ) ; C . mod ( this . order ) ; return C ; } genAttrBN ( attrs ) { const HAttr = [ ] ; for ( let i = 0 ; i < attrs . length ; i ++ ) { const t = this . getRandBN ( ) ; HAttr [ i ] = t ; } return HAttr ; } genAttrElement ( attrs ) { const HAttr = [ ] ; for ( let i = 0 ; i < attrs . length ; i ++ ) { const t = this . getRandG1 ( ) ; HAttr [ i ] = t ; } return HAttr ; } } /**
 * CryptoBase
 *  contains a refrence to a CryptoSuite instance.
 */ export class CryptoBase { param : CryptoSuite ; constructor ( param ) { this . param = param ; } } export class SecretKey extends CryptoBase { static GenerateSk ( param ) { const x = param . getRandBN ( ) ; const sk = new SecretKey ( param ) ; sk . setValue ( x ) ; return sk ; } value : any ; constructor ( param ) { super ( param ) ; this . value = new this . param . BIG ( 0 ) ; } setValue ( v ) { this . value . copy ( v ) ; } GenerateIssuerPublicKey ( ) { const x = this . value ; const w = this . param . PAIR . G2mul ( this . param . g2 , x ) ; let r = this . param . getRandBN ( ) ; const _g1 = this . param . PAIR . G1mul ( this . param . g1 , r ) ; const _g2 = this . param . PAIR . G1mul ( _g1 , x ) ; r = this . param . getRandBN ( ) ; const t1 = this . param . PAIR . G2mul ( this . param . g2 , r ) ; const t2 = this . param . PAIR . G1mul ( _g1 , r ) ; const C = this . param . hashToBN ( t1 , t2 , this . param . g2 , _g1 , w , _g2 ) ; const S = this . param . BIG . modmul ( C , x , this . param . order ) ; S . add ( r ) ; S . mod ( this . param . order ) ; const pi = { C , S } ; const pk = new IssuerPublicKey ( this . param ) ; pk . SetBasicValue ( w , _g1 , _g2 , pi ) ; return pk ; } ToBytes ( ) { if ( this . value === undefined ) { return '' ; } return this . value . toBytes ( ) ; } FromBytes ( s ) { this . value = this . param . BIG . fromBytes ( s ) ; return this . value . toString ( ) ; } Rand ( ) { const x = this . param . getRandBN ( ) ; this . setValue ( x ) ; } } export class IssuerPublicKey extends CryptoBase { static COPY ( target ) { const pk = new IssuerPublicKey ( target . param ) ; pk . SetBasicValue ( target . w , target . _g1 , target . _g2 , target . pi ) ; pk . SetAttrValue ( target . h0 , target . h_sk , target . h , target . attr ) ; return pk ; } w : any ; _g1 : any ; _g2 : any ; pi : { C : any ; S : any ; } ; h0 : any ; h_sk : any ; h : any ; attr : any [ ] ; constructor ( param ) { super ( param ) ; this . w = new this . param . ECP2 ( ) ; this . _g1 = new this . param . ECP ( ) ; this . _g2 = new this . param . ECP ( ) ; const C = new this . param . BIG ( ) ; const S = new this . param . BIG ( ) ; this . pi = { C , S } ; this . h0 = new this . param . ECP ( ) ; this . h_sk = new this . param . ECP ( ) ; this . attr = [ ] ; } SetBasicValue ( w , _g1 , _g2 , pi ) { this . w . copy ( w ) ; this . _g1 . copy ( _g1 ) ; this . _g2 . copy ( _g2 ) ; this . pi . C . copy ( pi . C ) ; this . pi . S . copy ( pi . S ) ; } SetAttrValue ( h0 , h_sk , h , attr ) { this . h0 . copy ( h0 ) ; this . h_sk . copy ( h_sk ) ; this . h = [ ] ; this . attr = [ ] ; for ( let i = 0 ; i < h . length ; i ++ ) { this . h [ i ] = new this . param . ECP ( ) ; this . h [ i ] . copy ( h [ i ] ) ; } for ( let i = 0 ; i < attr . length ; i ++ ) { this . attr [ i ] = attr [ i ] ; } } GenerateAttr ( AttributeName ) { const HAttr = this . param . genAttrElement ( AttributeName ) ; const h0 = this . param . getRandG1 ( ) ; const h_sk = this . param . getRandG1 ( ) ; const h = [ ] ; HAttr . forEach ( ( a ) => { h . push ( a ) ; } ) ; this . h0 = h0 ; this . h_sk = h_sk ; this . h = h ; this . attr = AttributeName ; } VerifyCredentialRequest ( CR ) { const C = new this . param . BIG ( 0 ) ; C . copy ( CR . pi . C ) ; const _t1 = this . param . PAIR . G1mul ( this . h_sk , CR . pi . S ) ; _t1 . add ( this . param . PAIR . G1mul ( CR . Nym , this . param . BIG . modneg ( C , this . param . order ) ) ) ; const _C = this . param . hashToBN ( _t1 , this . h_sk , CR . Nym , CR . nonce ) ; return this . param . BIG . comp ( CR . pi . C , _C ) === 0 ; } } /**
 * Credential
 *  The credential generated from issuer
 */ export class Credential extends CryptoBase { sig : { A : any ; B : any ; e : any ; s : any ; } ; attrs : any [ ] ; constructor ( param ) { super ( param ) ; const A = new this . param . ECP ( ) ; const B = new this . param . ECP ( ) ; const e = new this . param . BIG ( ) ; const s = new this . param . BIG ( ) ; this . sig = { A , B , e , s } ; this . attrs = [ ] ; } Set ( A , B , e , s , attrs ) { this . sig . A . copy ( A ) ; this . sig . B . copy ( B ) ; this . sig . e . copy ( e ) ; this . sig . s . copy ( s ) ; for ( let i = 0 ; i < attrs . length ; i ++ ) { this . attrs [ i ] = new this . param . BIG ( ) ; this . attrs [ i ] . copy ( attrs [ i ] ) ; } } Copy ( target ) { this . Set ( target . sig . A , target . sig . B , target . sig . e , target . sig . s , target . attrs ) ; } }