std::shared_ptr<Observable<typename Distribution::result_type>> Random( Engine e, Distribution d, Seeder s, Scheduler::shared scheduler = nullptr) { typedef typename Distribution::result_type T; if (!scheduler) {scheduler = std::make_shared<CurrentThreadScheduler>();} return CreateObservable<T>( [=](std::shared_ptr<Observer<T>> observer) -> Disposable { struct State { bool cancel; Engine e; Distribution d; T step() { return d(e); } }; auto state = std::make_shared<State>(); state->cancel = false; state->e = e; state->d = d; // allow the seed to be set s(state->e); ComposableDisposable cd; cd.Add(Disposable([=]{ state->cancel = true; })); cd.Add(scheduler->Schedule( fix0([=](Scheduler::shared s, std::function<Disposable(Scheduler::shared)> self) -> Disposable { if (state->cancel) return Disposable::Empty(); observer->OnNext(state->step()); return s->Schedule(std::move(self)); }))); return cd; }); }
int crypto_aead_decrypt( unsigned char *m,unsigned long long *mlen, // message unsigned char *nsec, // not relavent to CLOC or SLIC const unsigned char *c,unsigned long long clen, // ciphertext const unsigned char *ad,unsigned long long adlen, // associated data const unsigned char *npub, // nonce const unsigned char *k // the master key ) { block estate, tstate, tmp; // encryption state, tag state, and temporary state estate = SETZERO(); unsigned char ltag[16]; // local copy of temporary tag value unsigned long long i, lastblocklen,j; /* set ciphertext length */ *mlen = clen - CRYPTO_ABYTES; /* generate round keys from master key */ AES128_KeyExpansion(k); /* process the first (partial) block of ad */ load_partial_block(&estate, ad, (adlen>STATE_LEN)?STATE_LEN:adlen, ONE_ZERO_PADDING); fix0(estate); AES128_encrypt(estate, estate); if((ad[0] & 0x80) || (adlen == 0)){ // appy h h(estate); } else{ // do nothing } if(adlen > STATE_LEN){ // ad is of moer than one block i = STATE_LEN; /* process the middle ad blocks, excluding the first and last (partial) block */ while((i+STATE_LEN) < adlen) { tmp = LOAD(ad+i); estate = XOR(estate, tmp); AES128_encrypt(estate, estate); i += STATE_LEN; } /* process the last (partial) ad block */ load_partial_block(&tmp, ad+i, adlen - i, ONE_ZERO_PADDING); estate = XOR(estate, tmp); AES128_encrypt(estate, estate); } /* process the nonce */ load_partial_block(&tmp, npub, CRYPTO_NPUBBYTES, PARAM_OZP); estate = XOR(estate, tmp); if((adlen % STATE_LEN) || (adlen == 0)){ /* apply f2 */ f2(estate); } else{ /* apply f1 */ f1(estate); } /* process ciphertext */ tstate = estate; AES128_encrypt(estate, estate); if(*mlen){ /* apply g2 to tag state */ g2(tstate); } else{ /* apply g1 to tag state */ g1(tstate); } AES128_encrypt(tstate, tstate); i = 0; /* process all the message except for the last message/ciphertext block */ while((i + STATE_LEN) < (*mlen)){ tmp = LOAD(c+i); estate = XOR(estate, tmp); STORE(m+i, estate); tstate = XOR(tmp, tstate); AES128_encrypt(tstate, tstate); fix1(tmp); print_state("after applying fix1\n", estate); AES128_encrypt(tmp, estate); i += STATE_LEN; } /* process the last block of the message/ciphetext */ lastblocklen = (*mlen) - i; if(lastblocklen > 0){ load_partial_block(&tmp, c+i, lastblocklen, ZERO_APPEND); estate = XOR(estate, tmp); print_state("after xoring last partial message block\n", estate); store_partial_block(m+i, estate, lastblocklen); unsigned char shift_bytes = (STATE_LEN - (unsigned char)lastblocklen); tmp = AND(SHR(_mm_set1_epi8(0xff), shift_bytes), tmp); tstate = XOR(tstate, tmp); /* add the one zero padding */ tstate = XOR(tstate, SHL(_mm_set_epi8(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x80), lastblocklen)); if((*mlen) % STATE_LEN){ /* apply f2 */ f2(tstate); } else{ /* apply f1 */ f1(tstate); } AES128_encrypt(tstate, tstate); } /* compare tag and output message */ STORE(ltag, tstate); for(j = 0; j < CRYPTO_ABYTES; j++){ if(ltag[j] != c[clen - CRYPTO_ABYTES + j]) return RETURN_TAG_NO_MATCH; } return RETURN_SUCCESS; }