mirror of
https://github.com/Satsuoni/widevine-l3-guesser
synced 2025-02-25 00:15:23 +01:00
Added wasm code and some log examples
This commit is contained in:
commit
1aae32eb80
.gitignoreLICENSEREADME.mdbuild_wasm.batcontent_key_decryption.jscontent_script.js
docs
eme_interception.jslib
log_parsing
manifest.jsonmemory_dumps
Hasmulret18016d24d_639.gzLongstring_nearsha_621.gzLongstring_postfun_623.gzLongstring_postsha_622.gzLongstringproc_620.gzPeri.gzbollockrySnap.gz
protobuf-generated
wasm
wasm_src
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.vscode/*
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Tomer
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
54
README.md
Normal file
54
README.md
Normal file
@ -0,0 +1,54 @@
|
||||
# Trying to extract Widewine key: A journey to FaIlUrE
|
||||
|
||||
## Notes
|
||||
|
||||
- This work is based (obviously) on the [widevine-l3-decryptor extension](https://github.com/cryptonek/widevine-l3-decryptor). Many parts are the same, parts of Readme are a verbatim copy, etc.
|
||||
- I have no working knowledge of Chrome extension structure.
|
||||
- Some parts of code are copied from RFC documents, wikipedia, etc. *shrug*
|
||||
- Tldr: The result seems to work, but relies on code lifting into wasm module and lots of brute-forcing, resulting in about 15-minute wait for a single RSA decryption.
|
||||
- I am too lazy to improve on this.
|
||||
|
||||
## Introduction
|
||||
|
||||
[Widevine](https://www.widevine.com/solutions/widevine-drm) is a Google-owned DRM system that's in use by many popular streaming services (Netflix, Spotify, etc.) to prevent media content from being downloaded.
|
||||
|
||||
But Widevine's least secure security level, L3, as used in most browsers and PCs, is implemented 100% in software (i.e no hardware TEEs), thereby making it reversible and bypassable.
|
||||
|
||||
This Chrome extension demonstrates how it's possible to bypass Widevine DRM by hijacking calls to the browser's [Encrypted Media Extensions (EME)](https://www.html5rocks.com/en/tutorials/eme/basics) and (very slowly) decrypting all Widevine content keys transferred - effectively turning it into a clearkey DRM.
|
||||
|
||||
## Usage
|
||||
To see this concept in action, just load the extension in Developer Mode and browse to any website that plays Widevine-protected content, such as https://bitmovin.com/demos/drm _[Update: link got broken?]_.
|
||||
First, extension will try to brute-force input encoding for the code-lifted part, dumping progess to console. Then, assuming it succeeds, keys will be logged in plaintext to the javascript console.
|
||||
|
||||
e.g:
|
||||
|
||||
```
|
||||
WidevineDecryptor: Found key: 100b6c20940f779a4589152b57d2dacb (KID=eb676abbcb345e96bbcf616630f1a3da)
|
||||
```
|
||||
|
||||
Decrypting the media itself is then just a matter of using a tool that can decrypt MPEG-CENC streams, like `ffmpeg`.
|
||||
|
||||
e.g:
|
||||
|
||||
```
|
||||
ffmpeg -decryption_key 100b6c20940f779a4589152b57d2dacb -i encrypted_media.mp4 -codec copy decrypted_media.mp4
|
||||
```
|
||||
**NOTE**: The extension currently supports the Windows platform only.
|
||||
|
||||
## How I got here
|
||||
|
||||
### Starting point
|
||||
|
||||
### Reverse enginering and emulating
|
||||
|
||||
### Extracting part of the exponent
|
||||
|
||||
### Descending into despair
|
||||
|
||||
### Code lifting
|
||||
|
||||
### FaIlUrEs uPoN fAiLuReS
|
||||
|
||||
### Conclusion
|
||||
|
||||
|
1
build_wasm.bat
Normal file
1
build_wasm.bat
Normal file
@ -0,0 +1 @@
|
||||
emcc wasm_src/allocate.cpp wasm_src/misc.cpp wasm_src/integer.cpp wasm_src/algebra.cpp wasm_src/codelift.cpp -Os -s TOTAL_MEMORY=18743296 -Wno-implicitly-unsigned-literal -I "./wasm_src" -s WASM=1 -s LLD_REPORT_UNDEFINED -s "MODULARIZE=1" -s "EXPORT_NAME='WasmDsp'" -s "BINARYEN_METHOD='native-wasm'" -s "EXPORTED_FUNCTIONS=['_guessInput','_freeStr','_getOutput','_getDeoaep']" -s "EXPORTED_RUNTIME_METHODS=['stringToUTF8','UTF8ToString','stackSave','writeArrayToMemory','stackAlloc','stackRestore']" -o wasm/wasm_gsr.js
|
361
content_key_decryption.js
Normal file
361
content_key_decryption.js
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
This is where the magic happens
|
||||
*/
|
||||
|
||||
|
||||
var WidevineCrypto = {};
|
||||
var _freeStr, stringToUTF8, writeArrayToMemory, UTF8ToString, stackSave, stackRestore, stackAlloc;
|
||||
|
||||
|
||||
// Convert a hex string to a byte array
|
||||
function hexToBytes(hex) {
|
||||
for (var bytes = [], c = 0; c < hex.length; c += 2)
|
||||
bytes.push(parseInt(hex.substr(c, 2), 16));
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// Convert a byte array to a hex string
|
||||
function bytesToHex(bytes) {
|
||||
for (var hex = [], i = 0; i < bytes.length; i++) {
|
||||
var current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
|
||||
hex.push((current >>> 4).toString(16));
|
||||
hex.push((current & 0xF).toString(16));
|
||||
}
|
||||
return hex.join("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
(async function() {
|
||||
|
||||
// The public 2048-bit RSA key Widevine uses for Chrome devices in L3, on Windows
|
||||
WidevineCrypto.Module= await WasmDsp();
|
||||
await WidevineCrypto.Module.ready;
|
||||
_freeStr=WidevineCrypto.Module._freeStr;
|
||||
stringToUTF8=WidevineCrypto.Module.stringToUTF8;
|
||||
writeArrayToMemory=WidevineCrypto.Module.writeArrayToMemory;
|
||||
UTF8ToString=WidevineCrypto.Module.UTF8ToString;
|
||||
stackSave=WidevineCrypto.Module.stackSave;
|
||||
stackRestore=WidevineCrypto.Module.stackRestore;
|
||||
stackAlloc=WidevineCrypto.Module.stackAlloc;
|
||||
|
||||
WidevineCrypto.getCFunc = function (ident) {
|
||||
return this.Module[`_${ident}`]; // closure exported function
|
||||
}
|
||||
WidevineCrypto.scall = function (ident, returnType, argTypes, args, opts) {
|
||||
const toC = {
|
||||
string (str) {
|
||||
let ret = 0;
|
||||
if (str !== null && str !== undefined && str !== 0) {
|
||||
const len = (str.length << 2) + 1;
|
||||
ret = stackAlloc(len);
|
||||
stringToUTF8(str, ret, len);
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
array (arr) {
|
||||
const ret = stackAlloc(arr.length);
|
||||
writeArrayToMemory(arr, ret);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
function convertReturnValue (ret) {
|
||||
if (returnType === 'string') return UTF8ToString(ret);
|
||||
if (returnType === 'boolean') return Boolean(ret);
|
||||
return ret;
|
||||
}
|
||||
const func = this.getCFunc(ident);
|
||||
const cArgs = [];
|
||||
let stack = 0;
|
||||
if (args) {
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const converter = toC[argTypes[i]];
|
||||
if (converter) {
|
||||
if (stack === 0) stack = stackSave();
|
||||
cArgs[i] = converter(args[i]);
|
||||
} else {
|
||||
cArgs[i] = args[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
const _ret = func.apply(null, cArgs);
|
||||
const ret = convertReturnValue(_ret);
|
||||
_freeStr(_ret);
|
||||
if (stack !== 0) stackRestore(stack);
|
||||
return ret;
|
||||
}
|
||||
WidevineCrypto.swrap=function (ident, returnType, argTypes, opts) {
|
||||
argTypes = argTypes || [];
|
||||
const numericArgs = argTypes.every((type) => type === 'number');
|
||||
const numericRet = returnType !== 'string';
|
||||
if (numericRet && numericArgs && !opts) {
|
||||
return this.getCFunc(ident);
|
||||
}
|
||||
return function () {
|
||||
|
||||
return this.scall(ident, returnType, argTypes, arguments, opts);
|
||||
};
|
||||
}
|
||||
WidevineCrypto.guessInput = WidevineCrypto.swrap('guessInput', 'string', ['string']);
|
||||
WidevineCrypto.getOutput = WidevineCrypto.swrap('getOutput', 'string', ['string']);
|
||||
WidevineCrypto.getDeoaep = WidevineCrypto.swrap('getDeoaep', 'string', ['string']);
|
||||
|
||||
WidevineCrypto.chromeRSAPublicKey =
|
||||
`-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvKg9eT9JPEnfVYYS50x3
|
||||
MZirSQHyA2m/rxWY1x42LvE6ub47TU1zxjN4VC0jvrpWrU1YnB5/FR4lz296OPj/
|
||||
H/SR1dLfyXFhe22VWUBuOlEnsq693qll4N/PTFCuJByvnoe/4zsNthm1w5XjmG4x
|
||||
CjJ4+ZC0E5pCGvdLPk4VSCUN7I8XVbA45hBp4lR5g+2Th4VJtKn1+qG+9yp1qZKf
|
||||
pyQPseRrlYcXDvmTwpw18fFF5Vv+wN6F0rlAnWWZscNIv3bdRBq9UwM0deMmf5Fk
|
||||
fCWE2XTTrXuMDDNxFVbWws8jv3kFsXpoxiKgWApiPBr59EYpTV8t5Qch2F619Jtw
|
||||
EwIDAQAB
|
||||
-----END PUBLIC KEY-----`;
|
||||
|
||||
// The private 2048-bit RSA key Widevine uses for authenticating Chrome devices in L3, on Windows
|
||||
// Could not extract it completely, so resorted to clumsy code lifting
|
||||
|
||||
|
||||
WidevineCrypto.initializeKeys = async function()
|
||||
{
|
||||
// load the device RSA keys for various purposes
|
||||
this.publicKeyEncrypt = await crypto.subtle.importKey('spki', PEM2Binary(this.chromeRSAPublicKey), {name: 'RSA-OAEP', hash: { name: 'SHA-1' },}, true, ['encrypt']);
|
||||
this.publicKeyVerify = await crypto.subtle.importKey('spki', PEM2Binary(this.chromeRSAPublicKey), {name: 'RSA-PSS', hash: { name: 'SHA-1' },}, true, ['verify']);
|
||||
|
||||
this.keysInitialized = true;
|
||||
}
|
||||
WidevineCrypto.guessKey=async function(encKey)
|
||||
{
|
||||
let buf=new Uint8Array(1026);
|
||||
for(let i = 0; i < 1026; i++)
|
||||
{buf[i]=0;}
|
||||
|
||||
let hex=bytesToHex(encKey);
|
||||
let res="";
|
||||
console.log(hex);
|
||||
let o=2;
|
||||
while(o<1026)
|
||||
{
|
||||
let bt = Math.floor((o-2)/4);
|
||||
let offs = (o-2)%4;
|
||||
let desired=(encKey[encKey.length-bt-1]>>(offs*2))&3;
|
||||
let destail=hex.substr(hex.length-bt*2,bt*2);
|
||||
let val="";
|
||||
let j=0;
|
||||
for( j= buf[o]; j < 8; j++)
|
||||
{
|
||||
buf[o]=j;
|
||||
let st=bytesToHex(buf);
|
||||
val=await this.guessInput(st);
|
||||
|
||||
let sub=parseInt(val.substr(val.length-bt*2-2,2),16);
|
||||
let got=(sub>>(offs*2))&3;
|
||||
let gtail=val.substr(hex.length-bt*2,bt*2);
|
||||
if (got===desired && gtail===destail)
|
||||
{
|
||||
if(o%16==2)
|
||||
console.log(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == 8)
|
||||
{
|
||||
buf[o] = 0;
|
||||
o--;
|
||||
if (o < 2)
|
||||
{
|
||||
console.log("Could not match input");
|
||||
throw "Could not find proper input encoding";
|
||||
}
|
||||
buf[o]++;
|
||||
while (buf[o] == 8)
|
||||
{
|
||||
buf[o] = 0;
|
||||
o--;
|
||||
if (o < 2)
|
||||
{
|
||||
console.log("Could not match input");
|
||||
throw "Could not find proper input encoding";
|
||||
}
|
||||
buf[o]++;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
o++;
|
||||
|
||||
};
|
||||
console.log("Output");
|
||||
let st=bytesToHex(buf);
|
||||
let outp=await this.getDeoaep(st);
|
||||
console.log(outp);
|
||||
if(outp.length<10)
|
||||
{
|
||||
throw "Could not remove padding, probably invalid key"
|
||||
}
|
||||
console.log(st);
|
||||
return new Uint8Array(hexToBytes(outp));
|
||||
}
|
||||
|
||||
WidevineCrypto.decryptContentKey = async function(licenseRequest, licenseResponse)
|
||||
{
|
||||
licenseRequest = SignedMessage.read(new Pbf(licenseRequest));
|
||||
licenseResponse = SignedMessage.read(new Pbf(licenseResponse));
|
||||
//console.log("Decrypting?")
|
||||
//console.log("Request (from us)")
|
||||
console.log(licenseRequest)
|
||||
//console.log("Response")
|
||||
console.log(licenseResponse)
|
||||
if (licenseRequest.type != SignedMessage.MessageType.LICENSE_REQUEST.value) return;
|
||||
|
||||
license = License.read(new Pbf(licenseResponse.msg));
|
||||
|
||||
if (!this.keysInitialized) await this.initializeKeys();
|
||||
|
||||
// make sure the signature in the license request validates under the private key
|
||||
var signatureVerified = await window.crypto.subtle.verify({name: "RSA-PSS", saltLength: 20,}, this.publicKeyVerify,
|
||||
licenseRequest.signature, licenseRequest.msg)
|
||||
if (!signatureVerified)
|
||||
{
|
||||
console.log("Can't verify license request signature; either the platform is wrong or the key has changed!");
|
||||
return null;
|
||||
}
|
||||
var sessionKey=await this.guessKey(licenseResponse.session_key);
|
||||
// decrypt the session key
|
||||
// = await crypto.subtle.decrypt({name: "RSA-OAEP"}, this.privateKeyDecrypt, licenseResponse.session_key);
|
||||
|
||||
// calculate context_enc
|
||||
var encoder = new TextEncoder();
|
||||
var keySize = 128;
|
||||
var context_enc = concatBuffers([[0x01], encoder.encode("ENCRYPTION"), [0x00], licenseRequest.msg, intToBuffer(keySize)]);
|
||||
|
||||
// calculate encrypt_key using CMAC
|
||||
var encryptKey = wordToByteArray(
|
||||
CryptoJS.CMAC(arrayToWordArray(new Uint8Array(sessionKey)),
|
||||
arrayToWordArray(new Uint8Array(context_enc))).words);
|
||||
|
||||
// iterate the keys we got to find those we want to decrypt (the content key(s))
|
||||
var contentKeys = []
|
||||
for (currentKey of license.key)
|
||||
{
|
||||
if (currentKey.type != License.KeyContainer.KeyType.CONTENT.value) continue;
|
||||
|
||||
var keyId = currentKey.id;
|
||||
var keyData = currentKey.key.slice(0, 16);
|
||||
var keyIv = currentKey.iv.slice(0, 16);
|
||||
|
||||
// finally decrypt the content key
|
||||
var decryptedKey = wordToByteArray(
|
||||
CryptoJS.AES.decrypt({ ciphertext: arrayToWordArray(keyData) }, arrayToWordArray(encryptKey), { iv: arrayToWordArray(keyIv) }).words);
|
||||
|
||||
contentKeys.push(decryptedKey);
|
||||
console.log("WidevineDecryptor: Found key: " + toHexString(decryptedKey) + " (KID=" + toHexString(keyId) + ")");
|
||||
}
|
||||
|
||||
return contentKeys[0];
|
||||
}
|
||||
|
||||
//
|
||||
// Helper functions
|
||||
//
|
||||
|
||||
async function isRSAConsistent(publicKey, privateKey)
|
||||
{
|
||||
// See if the data is correctly decrypted after encryption
|
||||
var testData = new Uint8Array([0x41, 0x42, 0x43, 0x44]);
|
||||
var encryptedData = await crypto.subtle.encrypt({name: "RSA-OAEP"}, publicKey, testData);
|
||||
var testDecryptedData = await crypto.subtle.decrypt({name: "RSA-OAEP"}, privateKey, encryptedData);
|
||||
|
||||
return areBuffersEqual(testData, testDecryptedData);
|
||||
}
|
||||
|
||||
function areBuffersEqual(buf1, buf2)
|
||||
{
|
||||
if (buf1.byteLength != buf2.byteLength) return false;
|
||||
var dv1 = new Int8Array(buf1);
|
||||
var dv2 = new Int8Array(buf2);
|
||||
for (var i = 0 ; i != buf1.byteLength ; i++)
|
||||
{
|
||||
if (dv1[i] != dv2[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function concatBuffers(arrays)
|
||||
{
|
||||
// Get the total length of all arrays.
|
||||
let length = 0;
|
||||
arrays.forEach(item => {
|
||||
length += item.length;
|
||||
});
|
||||
|
||||
// Create a new array with total length and merge all source arrays.
|
||||
let mergedArray = new Uint8Array(length);
|
||||
let offset = 0;
|
||||
arrays.forEach(item => {
|
||||
mergedArray.set(new Uint8Array(item), offset);
|
||||
offset += item.length;
|
||||
});
|
||||
|
||||
return mergedArray;
|
||||
}
|
||||
|
||||
// CryptoJS format to byte array
|
||||
function wordToByteArray(wordArray)
|
||||
{
|
||||
var byteArray = [], word, i, j;
|
||||
for (i = 0; i < wordArray.length; ++i) {
|
||||
word = wordArray[i];
|
||||
for (j = 3; j >= 0; --j) {
|
||||
byteArray.push((word >> 8 * j) & 0xFF);
|
||||
}
|
||||
}
|
||||
return byteArray;
|
||||
}
|
||||
|
||||
// byte array to CryptoJS format
|
||||
function arrayToWordArray(u8Array)
|
||||
{
|
||||
var words = [], i = 0, len = u8Array.length;
|
||||
|
||||
while (i < len) {
|
||||
words.push(
|
||||
(u8Array[i++] << 24) |
|
||||
(u8Array[i++] << 16) |
|
||||
(u8Array[i++] << 8) |
|
||||
(u8Array[i++])
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
sigBytes: len,
|
||||
words: words
|
||||
};
|
||||
}
|
||||
|
||||
const toHexString = bytes => bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
|
||||
|
||||
const intToBuffer = num =>
|
||||
{
|
||||
let b = new ArrayBuffer(4);
|
||||
new DataView(b).setUint32(0, num);
|
||||
return Array.from(new Uint8Array(b));
|
||||
}
|
||||
|
||||
function PEM2Binary(pem)
|
||||
{
|
||||
var encoded = '';
|
||||
var lines = pem.split('\n');
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
if (lines[i].indexOf('-----') < 0) {
|
||||
encoded += lines[i];
|
||||
}
|
||||
}
|
||||
var byteStr = atob(encoded);
|
||||
var bytes = new Uint8Array(byteStr.length);
|
||||
for (var i = 0; i < byteStr.length; i++) {
|
||||
bytes[i] = byteStr.charCodeAt(i);
|
||||
}
|
||||
return bytes.buffer;
|
||||
}
|
||||
|
||||
}());
|
25
content_script.js
Normal file
25
content_script.js
Normal file
@ -0,0 +1,25 @@
|
||||
injectScripts();
|
||||
var Module=null;
|
||||
async function injectScripts()
|
||||
{
|
||||
await injectScript('lib/pbf.3.0.5.min.js');
|
||||
await injectScript('lib/cryptojs-aes_0.2.0.min.js');
|
||||
await injectScript('protobuf-generated/license_protocol.proto.js');
|
||||
await injectScript('wasm/wasm_gsr.js');
|
||||
await injectScript('content_key_decryption.js');
|
||||
await injectScript('eme_interception.js');
|
||||
}
|
||||
|
||||
function injectScript(scriptName)
|
||||
{
|
||||
return new Promise(function(resolve, reject)
|
||||
{
|
||||
var s = document.createElement('script');
|
||||
s.src = chrome.extension.getURL(scriptName);
|
||||
s.onload = function() {
|
||||
this.parentNode.removeChild(this);
|
||||
resolve(true);
|
||||
};
|
||||
(document.head||document.documentElement).appendChild(s);
|
||||
});
|
||||
}
|
BIN
docs/WidevineModularDRMSecurityIntegrationGuideforCENC.pdf
Normal file
BIN
docs/WidevineModularDRMSecurityIntegrationGuideforCENC.pdf
Normal file
Binary file not shown.
BIN
docs/Widevine_DRM_Architecture_Overview.pdf
Normal file
BIN
docs/Widevine_DRM_Architecture_Overview.pdf
Normal file
Binary file not shown.
407
eme_interception.js
Normal file
407
eme_interception.js
Normal file
@ -0,0 +1,407 @@
|
||||
/**
|
||||
* Hooks EME calls and forwards them for analysis and decryption.
|
||||
*
|
||||
* Most of the code here was borrowed from https://github.com/google/eme_logger/blob/master/eme_listeners.js
|
||||
*/
|
||||
|
||||
var lastReceivedLicenseRequest = null;
|
||||
var lastReceivedLicenseResponse = null;
|
||||
|
||||
/** Set up the EME listeners. */
|
||||
function startEMEInterception()
|
||||
{
|
||||
var listener = new EmeInterception();
|
||||
listener.setUpListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets called whenever an EME method is getting called or an EME event fires
|
||||
*/
|
||||
EmeInterception.onOperation = function(operationType, args)
|
||||
{
|
||||
//console.log(operationType);
|
||||
//console.log(args);
|
||||
if (operationType == "GenerateRequestCall")
|
||||
{
|
||||
// got initData
|
||||
//console.log(args);
|
||||
//console.log(args[1]);
|
||||
}
|
||||
else if (operationType == "MessageEvent")
|
||||
{
|
||||
var licenseRequest = args.message;
|
||||
lastReceivedLicenseRequest = licenseRequest;
|
||||
}
|
||||
else if (operationType == "UpdateCall")
|
||||
{
|
||||
var licenseResponse = args[0];
|
||||
var lmsg=SignedMessage.read(new Pbf(licenseResponse));
|
||||
//console.log(lmsg)
|
||||
lastReceivedLicenseResponse = licenseResponse;
|
||||
|
||||
// OK, let's try to decrypt it, assuming the response correlates to the request
|
||||
WidevineCrypto.decryptContentKey(lastReceivedLicenseRequest, lastReceivedLicenseResponse);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Manager for EME event and method listeners.
|
||||
* @constructor
|
||||
*/
|
||||
function EmeInterception()
|
||||
{
|
||||
this.unprefixedEmeEnabled = Navigator.prototype.requestMediaKeySystemAccess ? true : false;
|
||||
this.prefixedEmeEnabled = HTMLMediaElement.prototype.webkitGenerateKeyRequest ? true : false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The number of types of HTML Media Elements to track.
|
||||
* @const {number}
|
||||
*/
|
||||
EmeInterception.NUM_MEDIA_ELEMENT_TYPES = 3;
|
||||
|
||||
|
||||
/**
|
||||
* Sets up EME listeners for whichever type of EME is enabled.
|
||||
*/
|
||||
EmeInterception.prototype.setUpListeners = function()
|
||||
{
|
||||
if (!this.unprefixedEmeEnabled && !this.prefixedEmeEnabled) {
|
||||
// EME is not enabled, just ignore
|
||||
return;
|
||||
}
|
||||
if (this.unprefixedEmeEnabled) {
|
||||
this.addListenersToNavigator_();
|
||||
}
|
||||
if (this.prefixedEmeEnabled) {
|
||||
// Prefixed EME is enabled
|
||||
}
|
||||
this.addListenersToAllEmeElements_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds listeners to the EME methods on the Navigator object.
|
||||
* @private
|
||||
*/
|
||||
EmeInterception.prototype.addListenersToNavigator_ = function()
|
||||
{
|
||||
if (navigator.listenersAdded_)
|
||||
return;
|
||||
|
||||
var originalRequestMediaKeySystemAccessFn = EmeInterception.extendEmeMethod(
|
||||
navigator,
|
||||
navigator.requestMediaKeySystemAccess,
|
||||
"RequestMediaKeySystemAccessCall");
|
||||
|
||||
navigator.requestMediaKeySystemAccess = function()
|
||||
{
|
||||
var options = arguments[1];
|
||||
|
||||
// slice "It is recommended that a robustness level be specified" warning
|
||||
var modifiedArguments = arguments;
|
||||
var modifiedOptions = EmeInterception.addRobustnessLevelIfNeeded(options);
|
||||
modifiedArguments[1] = modifiedOptions;
|
||||
|
||||
var result = originalRequestMediaKeySystemAccessFn.apply(null, modifiedArguments);
|
||||
// Attach listeners to returned MediaKeySystemAccess object
|
||||
return result.then(function(mediaKeySystemAccess)
|
||||
{
|
||||
this.addListenersToMediaKeySystemAccess_(mediaKeySystemAccess);
|
||||
return Promise.resolve(mediaKeySystemAccess);
|
||||
}.bind(this));
|
||||
|
||||
}.bind(this);
|
||||
|
||||
navigator.listenersAdded_ = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds listeners to the EME methods on a MediaKeySystemAccess object.
|
||||
* @param {MediaKeySystemAccess} mediaKeySystemAccess A MediaKeySystemAccess
|
||||
* object to add listeners to.
|
||||
* @private
|
||||
*/
|
||||
EmeInterception.prototype.addListenersToMediaKeySystemAccess_ = function(mediaKeySystemAccess)
|
||||
{
|
||||
if (mediaKeySystemAccess.listenersAdded_) {
|
||||
return;
|
||||
}
|
||||
mediaKeySystemAccess.originalGetConfiguration = mediaKeySystemAccess.getConfiguration;
|
||||
mediaKeySystemAccess.getConfiguration = EmeInterception.extendEmeMethod(
|
||||
mediaKeySystemAccess,
|
||||
mediaKeySystemAccess.getConfiguration,
|
||||
"GetConfigurationCall");
|
||||
|
||||
var originalCreateMediaKeysFn = EmeInterception.extendEmeMethod(
|
||||
mediaKeySystemAccess,
|
||||
mediaKeySystemAccess.createMediaKeys,
|
||||
"CreateMediaKeysCall");
|
||||
|
||||
mediaKeySystemAccess.createMediaKeys = function()
|
||||
{
|
||||
var result = originalCreateMediaKeysFn.apply(null, arguments);
|
||||
// Attach listeners to returned MediaKeys object
|
||||
return result.then(function(mediaKeys) {
|
||||
mediaKeys.keySystem_ = mediaKeySystemAccess.keySystem;
|
||||
this.addListenersToMediaKeys_(mediaKeys);
|
||||
return Promise.resolve(mediaKeys);
|
||||
}.bind(this));
|
||||
|
||||
}.bind(this);
|
||||
|
||||
mediaKeySystemAccess.listenersAdded_ = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds listeners to the EME methods on a MediaKeys object.
|
||||
* @param {MediaKeys} mediaKeys A MediaKeys object to add listeners to.
|
||||
* @private
|
||||
*/
|
||||
EmeInterception.prototype.addListenersToMediaKeys_ = function(mediaKeys)
|
||||
{
|
||||
if (mediaKeys.listenersAdded_) {
|
||||
return;
|
||||
}
|
||||
var originalCreateSessionFn = EmeInterception.extendEmeMethod(mediaKeys, mediaKeys.createSession, "CreateSessionCall");
|
||||
mediaKeys.createSession = function()
|
||||
{
|
||||
var result = originalCreateSessionFn.apply(null, arguments);
|
||||
result.keySystem_ = mediaKeys.keySystem_;
|
||||
// Attach listeners to returned MediaKeySession object
|
||||
this.addListenersToMediaKeySession_(result);
|
||||
return result;
|
||||
}.bind(this);
|
||||
|
||||
mediaKeys.setServerCertificate = EmeInterception.extendEmeMethod(mediaKeys, mediaKeys.setServerCertificate, "SetServerCertificateCall");
|
||||
mediaKeys.listenersAdded_ = true;
|
||||
};
|
||||
|
||||
|
||||
/** Adds listeners to the EME methods and events on a MediaKeySession object.
|
||||
* @param {MediaKeySession} session A MediaKeySession object to add
|
||||
* listeners to.
|
||||
* @private
|
||||
*/
|
||||
EmeInterception.prototype.addListenersToMediaKeySession_ = function(session)
|
||||
{
|
||||
if (session.listenersAdded_) {
|
||||
return;
|
||||
}
|
||||
|
||||
session.generateRequest = EmeInterception.extendEmeMethod(session,session.generateRequest, "GenerateRequestCall");
|
||||
session.load = EmeInterception.extendEmeMethod(session, session.load, "LoadCall");
|
||||
session.update = EmeInterception.extendEmeMethod(session,session.update, "UpdateCall");
|
||||
session.close = EmeInterception.extendEmeMethod(session, session.close, "CloseCall");
|
||||
session.remove = EmeInterception.extendEmeMethod(session, session.remove, "RemoveCall");
|
||||
|
||||
session.addEventListener('message', function(e)
|
||||
{
|
||||
e.keySystem = session.keySystem_;
|
||||
EmeInterception.interceptEvent("MessageEvent", e);
|
||||
});
|
||||
|
||||
session.addEventListener('keystatuseschange', EmeInterception.interceptEvent.bind(null, "KeyStatusesChangeEvent"));
|
||||
|
||||
session.listenersAdded_ = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds listeners to all currently created media elements (audio, video) and sets up a
|
||||
* mutation-summary observer to add listeners to any newly created media
|
||||
* elements.
|
||||
* @private
|
||||
*/
|
||||
EmeInterception.prototype.addListenersToAllEmeElements_ = function()
|
||||
{
|
||||
this.addEmeInterceptionToInitialMediaElements_();
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds listeners to the EME elements currently in the document.
|
||||
* @private
|
||||
*/
|
||||
EmeInterception.prototype.addEmeInterceptionToInitialMediaElements_ = function()
|
||||
{
|
||||
var audioElements = document.getElementsByTagName('audio');
|
||||
for (var i = 0; i < audioElements.length; ++i) {
|
||||
this.addListenersToEmeElement_(audioElements[i], false);
|
||||
}
|
||||
var videoElements = document.getElementsByTagName('video');
|
||||
for (var i = 0; i < videoElements.length; ++i) {
|
||||
this.addListenersToEmeElement_(videoElements[i], false);
|
||||
}
|
||||
var mediaElements = document.getElementsByTagName('media');
|
||||
for (var i = 0; i < mediaElements.length; ++i) {
|
||||
this.addListenersToEmeElement_(mediaElements[i], false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds method and event listeners to media element.
|
||||
* @param {HTMLMediaElement} element A HTMLMedia element to add listeners to.
|
||||
* @private
|
||||
*/
|
||||
EmeInterception.prototype.addListenersToEmeElement_ = function(element)
|
||||
{
|
||||
this.addEmeEventListeners_(element);
|
||||
this.addEmeMethodListeners_(element);
|
||||
console.info('EME listeners successfully added to:', element);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds event listeners to a media element.
|
||||
* @param {HTMLMediaElement} element A HTMLMedia element to add listeners to.
|
||||
* @private
|
||||
*/
|
||||
EmeInterception.prototype.addEmeEventListeners_ = function(element)
|
||||
{
|
||||
if (element.eventListenersAdded_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.prefixedEmeEnabled)
|
||||
{
|
||||
element.addEventListener('webkitneedkey', EmeInterception.interceptEvent.bind(null, "NeedKeyEvent"));
|
||||
element.addEventListener('webkitkeymessage', EmeInterception.interceptEvent.bind(null, "KeyMessageEvent"));
|
||||
element.addEventListener('webkitkeyadded', EmeInterception.interceptEvent.bind(null, "KeyAddedEvent"));
|
||||
element.addEventListener('webkitkeyerror', EmeInterception.interceptEvent.bind(null, "KeyErrorEvent"));
|
||||
}
|
||||
|
||||
element.addEventListener('encrypted', EmeInterception.interceptEvent.bind(null, "EncryptedEvent"));
|
||||
element.addEventListener('play', EmeInterception.interceptEvent.bind(null, "PlayEvent"));
|
||||
|
||||
element.addEventListener('error', function(e) {
|
||||
console.error('Error Event');
|
||||
EmeInterception.interceptEvent("ErrorEvent", e);
|
||||
});
|
||||
|
||||
element.eventListenersAdded_ = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds method listeners to a media element.
|
||||
* @param {HTMLMediaElement} element A HTMLMedia element to add listeners to.
|
||||
* @private
|
||||
*/
|
||||
EmeInterception.prototype.addEmeMethodListeners_ = function(element)
|
||||
{
|
||||
if (element.methodListenersAdded_) {
|
||||
return;
|
||||
}
|
||||
|
||||
element.play = EmeInterception.extendEmeMethod(element, element.play, "PlayCall");
|
||||
|
||||
if (this.prefixedEmeEnabled) {
|
||||
element.canPlayType = EmeInterception.extendEmeMethod(element, element.canPlayType, "CanPlayTypeCall");
|
||||
|
||||
element.webkitGenerateKeyRequest = EmeInterception.extendEmeMethod(element, element.webkitGenerateKeyRequest, "GenerateKeyRequestCall");
|
||||
element.webkitAddKey = EmeInterception.extendEmeMethod(element, element.webkitAddKey, "AddKeyCall");
|
||||
element.webkitCancelKeyRequest = EmeInterception.extendEmeMethod(element, element.webkitCancelKeyRequest, "CancelKeyRequestCall");
|
||||
|
||||
}
|
||||
|
||||
if (this.unprefixedEmeEnabled) {
|
||||
element.setMediaKeys = EmeInterception.extendEmeMethod(element, element.setMediaKeys, "SetMediaKeysCall");
|
||||
}
|
||||
|
||||
element.methodListenersAdded_ = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a wrapper function that logs calls to the given method.
|
||||
* @param {!Object} element An element or object whose function
|
||||
* call will be logged.
|
||||
* @param {!Function} originalFn The function to log.
|
||||
* @param {!Function} type The constructor for a logger class that will
|
||||
* be instantiated to log the originalFn call.
|
||||
* @return {!Function} The new version, with logging, of orginalFn.
|
||||
*/
|
||||
EmeInterception.extendEmeMethod = function(element, originalFn, type)
|
||||
{
|
||||
return function()
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = originalFn.apply(element, arguments);
|
||||
var args = [].slice.call(arguments);
|
||||
EmeInterception.interceptCall(type, args, result, element);
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Intercepts a method call to the console and a separate frame.
|
||||
* @param {!Function} constructor The constructor for a logger class that will
|
||||
* be instantiated to log this call.
|
||||
* @param {Array} args The arguments this call was made with.
|
||||
* @param {Object} result The result of this method call.
|
||||
* @param {!Object} target The element this method was called on.
|
||||
* @return {!eme.EmeMethodCall} The data that has been logged.
|
||||
*/
|
||||
EmeInterception.interceptCall = function(type, args, result, target)
|
||||
{
|
||||
EmeInterception.onOperation(type, args);
|
||||
return args;
|
||||
};
|
||||
|
||||
/**
|
||||
* Intercepts an event to the console and a separate frame.
|
||||
* @param {!Function} constructor The constructor for a logger class that will
|
||||
* be instantiated to log this event.
|
||||
* @param {!Event} event An EME event.
|
||||
* @return {!eme.EmeEvent} The data that has been logged.
|
||||
*/
|
||||
EmeInterception.interceptEvent = function(type, event)
|
||||
{
|
||||
EmeInterception.onOperation(type, event);
|
||||
return event;
|
||||
};
|
||||
|
||||
EmeInterception.addRobustnessLevelIfNeeded = function(options)
|
||||
{
|
||||
for (var i = 0; i < options.length; i++)
|
||||
{
|
||||
var option = options[i];
|
||||
var videoCapabilities = option["videoCapabilities"];
|
||||
var audioCapabilties = option["audioCapabilities"];
|
||||
if (videoCapabilities != null)
|
||||
{
|
||||
for (var j = 0; j < videoCapabilities.length; j++)
|
||||
if (videoCapabilities[j]["robustness"] == undefined) videoCapabilities[j]["robustness"] = "SW_SECURE_CRYPTO";
|
||||
}
|
||||
|
||||
if (audioCapabilties != null)
|
||||
{
|
||||
for (var j = 0; j < audioCapabilties.length; j++)
|
||||
if (audioCapabilties[j]["robustness"] == undefined) audioCapabilties[j]["robustness"] = "SW_SECURE_CRYPTO";
|
||||
}
|
||||
|
||||
option["videoCapabilities"] = videoCapabilities;
|
||||
option["audioCapabilities"] = audioCapabilties;
|
||||
options[i] = option;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
startEMEInterception();
|
43
lib/cryptojs-aes_0.2.0.min.js
vendored
Normal file
43
lib/cryptojs-aes_0.2.0.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
lib/pbf.3.0.5.min.js
vendored
Normal file
1
lib/pbf.3.0.5.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
log_parsing/exp_values.json
Normal file
1
log_parsing/exp_values.json
Normal file
File diff suppressed because one or more lines are too long
25142
log_parsing/exponentiation.log
Normal file
25142
log_parsing/exponentiation.log
Normal file
File diff suppressed because one or more lines are too long
121
log_parsing/prfnd.py
Normal file
121
log_parsing/prfnd.py
Normal file
@ -0,0 +1,121 @@
|
||||
# use on the appropriate log file produced by ghidra
|
||||
import sys
|
||||
fl=sys.argv[1]
|
||||
def modInverse(a, m):
|
||||
m0 = m
|
||||
y = 0
|
||||
x = 1
|
||||
if (m == 1):
|
||||
return 0
|
||||
while (a > 1):
|
||||
q = a // m
|
||||
t = m
|
||||
m = a % m
|
||||
a = t
|
||||
t = y
|
||||
y = x - q * y
|
||||
x = t
|
||||
if (x < 0):
|
||||
x = x + m0
|
||||
return x
|
||||
n=0xBCA83D793F493C49DF558612E74C773198AB4901F20369BFAF1598D71E362EF13AB9BE3B4D4D73C63378542D23BEBA56AD4D589C1E7F151E25CF6F7A38F8FF1FF491D5D2DFC971617B6D9559406E3A5127B2AEBDDEA965E0DFCF4C50AE241CAF9E87BFE33B0DB619B5C395E3986E310A3278F990B4139A421AF74B3E4E1548250DEC8F1755B038E61069E2547983ED93878549B4A9F5FAA1BEF72A75A9929FA7240FB1E46B9587170EF993C29C35F1F145E55BFEC0DE85D2B9409D6599B1C348BF76DD441ABD53033475E3267F91647C2584D974D3AD7B8C0C33711556D6C2CF23BF7905B17A68C622A0580A623C1AF9F446294D5F2DE50721D85EB5F49B7013
|
||||
rt=0x79bad423a3b14693488f32a3f32ca9cf96dbdfc5b45c7d4bba04af8958f008e3b7468b33f0f868eccc0b5b0fac5c60d131c2491b43dda75af695cfc303086204cb656f24b02024adef05c5e3be2f4918b67f7c75d3b9150b78ba70f4785515bd64e2905517559033e69a4a36501604c371a37137f56d64444b269538b87152169bf581d560bab993e4a6010f39f41fc97396f57eaecef874a469d5159ab5a71f6c9c5e1e4e7e5de2a7436604f47c695572b7b8916116044ba223c95eccaad9c3747dcdc56e966b1978a17282d9911d9bf314f1ef52971d4c4f59c1fcde5c4deeeb8ce02816aa24b79091d81e70c11c3f12dafad70b74eee3aa4a902a2d76b2bc
|
||||
r=(1<<2048)
|
||||
ri=modInverse(r,n)
|
||||
rii=modInverse(ri,n)
|
||||
|
||||
accs=["Collected as HasMulAdd ,a : ",
|
||||
"Collected as SubN ,a : ",
|
||||
"Collected as Plus ,b : " ,
|
||||
"Collected as Plum? ,b : ",
|
||||
"Collected as Plum res ,b : ",
|
||||
"Collected as Plus ,a : ",
|
||||
"Collected as YetAnother ,a : ",
|
||||
"Collected as MbSubtr ,a : ",
|
||||
"Collected as Upper ,a : ",
|
||||
"Collected as MbSubtr ,b : ",
|
||||
"Grabbed "
|
||||
]
|
||||
priors=[]
|
||||
mults={}
|
||||
pluses={}
|
||||
minuses={}
|
||||
sqms={}
|
||||
sqms2={}
|
||||
relations={}
|
||||
|
||||
def checkPriorRelation(nm):
|
||||
global priors
|
||||
if nm in priors: return
|
||||
rel=False
|
||||
if nm in mults:
|
||||
relations[nm]=["mul",mults[nm]]
|
||||
del mults[nm]
|
||||
rel=True
|
||||
if nm in pluses and not rel:
|
||||
print("Sum")
|
||||
relations[nm]=["sum",pluses[nm]]
|
||||
del pluses[nm]
|
||||
rel=True
|
||||
if nm in minuses and not rel:
|
||||
print("Neg")
|
||||
relations[nm]=["neg",minuses[nm]]
|
||||
del minuses[nm]
|
||||
rel=True
|
||||
if rel is False:
|
||||
if nm in sqms:
|
||||
relations[nm]=["sqm",sqms[nm]]
|
||||
if rel is False:
|
||||
if nm in sqms2:
|
||||
print("Squam2")
|
||||
relations[nm]=["sqm2",sqms2[nm]]
|
||||
priors.append(nm)
|
||||
for k in range(len(priors)):
|
||||
p=priors[k]
|
||||
mi=(p*nm*ri)%n
|
||||
sqm=(p*mi*ri)%n
|
||||
sqm2=(nm*mi*ri)%n
|
||||
mp=(p+nm)%n
|
||||
mn=(p-nm+n)%n
|
||||
mn2=(nm-p+n)%n
|
||||
if nm<0: mn+=n
|
||||
if not mi in mults:
|
||||
mults[mi]=[k,len(priors)-1]
|
||||
if not mp in pluses:
|
||||
pluses[mp]=[k,len(priors)-1]
|
||||
if not mn in minuses:
|
||||
minuses[mn]=[k,len(priors)-1]
|
||||
if not mn2 in minuses:
|
||||
minuses[mn2]=[len(priors)-1,k]
|
||||
|
||||
lnm=0
|
||||
|
||||
def save():
|
||||
import json
|
||||
st=json.dumps({"priors":priors, "relations":relations})
|
||||
fl=open("exp_values.json","w")
|
||||
fl.write(st)
|
||||
fl.close()
|
||||
cnt=0
|
||||
prev=None
|
||||
with open(fl,"r",encoding="utf-8") as fl:
|
||||
for ln in fl:
|
||||
for acc in accs:
|
||||
if acc in ln:
|
||||
if "Grabbed " in ln:
|
||||
nm=int(ln.split(":")[1].strip(),16)%n
|
||||
else:
|
||||
nm=int(ln[len(acc):],16)%n
|
||||
lnm=nm
|
||||
if nm in priors:
|
||||
print("Prior")
|
||||
else:
|
||||
pass
|
||||
checkPriorRelation(nm)
|
||||
prev=nm
|
||||
cnt=cnt+1
|
||||
if cnt>100:
|
||||
cnt=0
|
||||
save()
|
||||
break
|
||||
save()
|
274
log_parsing/prfold.py
Normal file
274
log_parsing/prfold.py
Normal file
@ -0,0 +1,274 @@
|
||||
# run this with json file from previous step
|
||||
import sys
|
||||
import json
|
||||
def modInverse(a, m):
|
||||
m0=m
|
||||
y=0
|
||||
x=1
|
||||
if (m == 1):
|
||||
return 0
|
||||
while (a > 1):
|
||||
q=a // m
|
||||
t=m
|
||||
m=a % m
|
||||
a=t
|
||||
t=y
|
||||
y= x - q * y
|
||||
x= t
|
||||
if (x < 0):
|
||||
x= x + m0
|
||||
return x
|
||||
fl=sys.argv[1]
|
||||
with open(fl,"r") as f:
|
||||
data=json.loads(f.read())
|
||||
priors=data["priors"]
|
||||
trees={}
|
||||
|
||||
|
||||
n=0xBCA83D793F493C49DF558612E74C773198AB4901F20369BFAF1598D71E362EF13AB9BE3B4D4D73C63378542D23BEBA56AD4D589C1E7F151E25CF6F7A38F8FF1FF491D5D2DFC971617B6D9559406E3A5127B2AEBDDEA965E0DFCF4C50AE241CAF9E87BFE33B0DB619B5C395E3986E310A3278F990B4139A421AF74B3E4E1548250DEC8F1755B038E61069E2547983ED93878549B4A9F5FAA1BEF72A75A9929FA7240FB1E46B9587170EF993C29C35F1F145E55BFEC0DE85D2B9409D6599B1C348BF76DD441ABD53033475E3267F91647C2584D974D3AD7B8C0C33711556D6C2CF23BF7905B17A68C622A0580A623C1AF9F446294D5F2DE50721D85EB5F49B7013
|
||||
r=(1<<2048)
|
||||
ri=modInverse(r,n)
|
||||
rii=modInverse(ri,n)
|
||||
endpoint=priors[-1]
|
||||
stp=pow(endpoint,65537,n)
|
||||
donotexpand=[0] #,25,61,80,98,216
|
||||
droot=5
|
||||
|
||||
class rootNode(object): #for single root with additions
|
||||
def __init__(self):
|
||||
self.snodes=[[droot,1]]
|
||||
class expNode(object):
|
||||
def __init__(self):
|
||||
self.numconst=1
|
||||
self.subnodes={}
|
||||
def getVal(self):
|
||||
vl=self.numconst
|
||||
for sn in self.subnodes:
|
||||
if sn>=0:
|
||||
k=pow(priors[sn],self.subnodes[sn],n)%n
|
||||
vl=vl*k%n
|
||||
return vl%n
|
||||
def asConst(self, cnst):
|
||||
self.numconst=cnst
|
||||
self.subnodes={}
|
||||
return self
|
||||
def asNode(self, nd):
|
||||
self.numconst=1
|
||||
self.subnodes={nd:1}
|
||||
return self
|
||||
def asCopy(self,other):
|
||||
self.numconst=other.numconst
|
||||
self.subnodes={}
|
||||
for nd in other.subnodes:
|
||||
self.subnodes[nd]=other.subnodes[nd]
|
||||
return self
|
||||
def canAdd(self,other):
|
||||
if len(self.subnodes)!=len(other.subnodes): return False
|
||||
for sn in self.subnodes:
|
||||
if not sn in other.subnodes: return False
|
||||
if self.subnodes[sn]!=other.subnodes[sn]: return False
|
||||
return True
|
||||
def add(self,other):
|
||||
ret=expNode()
|
||||
ret.numconst=(self.numconst+other.numconst)%n
|
||||
ret.subnodes=self.subnodes.copy()
|
||||
return ret
|
||||
def convertToConst(self,num,val):
|
||||
if not num in self.subnodes: return
|
||||
pwr=pow(val,self.subnodes[num],n)*pow(ri,self.subnodes[num]-1,n)%n
|
||||
self.numconst=(self.numconst*pwr)%n
|
||||
del self.subnodes[num]
|
||||
def __repr__(self):
|
||||
return "{}".format(self.subnodes)
|
||||
def mul(self,other):
|
||||
ret=expNode()
|
||||
ret.numconst=self.numconst*other.numconst*ri%n
|
||||
st=set(self.subnodes.keys())|set(other.subnodes.keys())
|
||||
for vl in st:
|
||||
a1=self.subnodes.get(vl,0)
|
||||
a2=other.subnodes.get(vl,0)
|
||||
if vl>=0:
|
||||
ret.subnodes[vl]=a1+a2
|
||||
else:
|
||||
if a1+a2<=1:
|
||||
ret.subnodes[vl]=a1+a2
|
||||
else:
|
||||
ret.numconst=0
|
||||
return ret
|
||||
def reduceList(lst):
|
||||
ret=[]
|
||||
lc=list(lst)
|
||||
while len(lc)>0:
|
||||
cr=lc.pop()
|
||||
rl=[]
|
||||
for pt in lc:
|
||||
if cr.canAdd(pt):
|
||||
cr=cr.add(pt)
|
||||
else:
|
||||
rl.append(pt)
|
||||
lc=rl
|
||||
if cr.numconst>0:
|
||||
ret.append(cr)
|
||||
return ret
|
||||
|
||||
def mulList(ls1,ls2):
|
||||
retl=[]
|
||||
for a in ls1:
|
||||
for b in ls2:
|
||||
retl.append(a.mul(b))
|
||||
if len(ls1)>0 and len(ls2)>0:
|
||||
return reduceList(retl)
|
||||
else:
|
||||
return retl
|
||||
|
||||
class expVariable(object):
|
||||
def __init__(self,num,nodes,priors,rel):
|
||||
self.num=num
|
||||
self.nodes=[]
|
||||
if rel is None:
|
||||
self.nodes=[expNode().asConst(priors[num])]
|
||||
return
|
||||
if rel=="root":
|
||||
self.nodes=[expNode().asNode(num)]
|
||||
return
|
||||
if rel=="ism":
|
||||
self.nodes=[expNode().asNode(-1),expNode().asNode(-2)]
|
||||
return
|
||||
nd1=nodes[rel[1][0]]
|
||||
nd2=nodes[rel[1][1]]
|
||||
if rel[0]=="mul":
|
||||
self.nodes=mulList(nd1.nodes,nd2.nodes)
|
||||
elif rel[0]=="sum":
|
||||
ndlist=[expNode().asCopy(n) for n in nd1.nodes]+[expNode().asCopy(n) for n in nd2.nodes]
|
||||
self.nodes=reduceList(ndlist)
|
||||
elif rel[0]=="neg":
|
||||
cnst=expNode().asConst((n-1)*r%n)
|
||||
ndlist=[expNode().asCopy(n) for n in nd1.nodes]+[n.mul(cnst) for n in nd2.nodes]
|
||||
self.nodes=reduceList(ndlist)
|
||||
def spow(self):
|
||||
ndlist=[kn.mul(expNode().asConst(r*r%n)) for kn in self.nodes]
|
||||
ndlist2=mulList(ndlist,ndlist) # ^2
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist2=mulList(ndlist2,ndlist2)
|
||||
ndlist=mulList(ndlist,ndlist2)
|
||||
lst=[kn.mul(expNode().asConst(1)) for kn in ndlist]
|
||||
print(lst)
|
||||
print("{:x}".format(lst[0].numconst))
|
||||
print("{:x}".format(lst[1].numconst))
|
||||
ret=expVariable(-2,nodes,priors,None)
|
||||
ret.nodes=lst
|
||||
return ret
|
||||
|
||||
|
||||
for p in priors:
|
||||
print("{}: {:x}".format(priors.index(p),p))
|
||||
print("> {:x}".format(p*ri%n))
|
||||
print("> {:x}".format(modInverse(p*ri%n,n)))
|
||||
if "relations" in data:
|
||||
rels={}
|
||||
for et in data["relations"]:
|
||||
rels[int(et)]=data["relations"][et]
|
||||
lst=[priors.index(endpoint)]
|
||||
awl=set([])
|
||||
while len(lst)>0:
|
||||
kp=lst[0]
|
||||
lst=lst[1:]
|
||||
if kp in awl: continue
|
||||
awl.add(kp)
|
||||
kpp=priors[kp]
|
||||
if kpp in rels:
|
||||
for k in rels[kpp][1]:
|
||||
if not k in awl:
|
||||
lst.append(k)
|
||||
|
||||
nodes={}
|
||||
disms=[]
|
||||
for k in range(0,len(priors),1):
|
||||
ld=expVariable(k,nodes,priors,rels.get(priors[k],None))
|
||||
if len (ld.nodes)>100 and len(disms)==0:
|
||||
donotexpand.append(k)
|
||||
print("Adding as node {}".format(k))
|
||||
if k in disms:
|
||||
nd=expVariable(k,nodes,priors,"ism")
|
||||
nd.nodes.append(expNode().asConst(priors[k]))
|
||||
#nd=expVariable(k,nodes,priors,None)
|
||||
elif k in donotexpand:
|
||||
nd=expVariable(k,nodes,priors,"root")
|
||||
else:
|
||||
#print(rels.get(priors[k],None))
|
||||
nd=expVariable(k,nodes,priors,rels.get(priors[k],None))
|
||||
nodes[k]=nd
|
||||
print("{}: {}".format(k,rels.get(priors[k],None)))
|
||||
print("{}: {} -> {}".format(k,nd.nodes,len(nd.nodes)))
|
||||
#if k==len(priors)-1:
|
||||
for nod in nd.nodes:
|
||||
print("{:x}".format(nod.numconst))
|
||||
if len(nd.nodes)==1:
|
||||
print("{:x}".format(nd.nodes[0].getVal()))
|
||||
if False:#k==len(priors)-1:
|
||||
ec=pow(12,65537,n)
|
||||
a=priors[25]
|
||||
for s in range(29,4385,1):
|
||||
nd=nodes[s]
|
||||
if len(nd.nodes)!=2: continue
|
||||
print(s)
|
||||
if len(nd.nodes[0].subnodes)==0:
|
||||
res=nd.nodes[0].numconst
|
||||
der=nd.nodes[1].numconst
|
||||
else:
|
||||
res=nd.nodes[1].numconst
|
||||
der=nd.nodes[0].numconst
|
||||
print("Res: {:x}".format(res))
|
||||
print("Der: {:x}".format(der))
|
||||
print("Aaa: {:x}".format(a))
|
||||
dk=der*a*modInverse(res,n)%n
|
||||
#dk=dk*ri%n
|
||||
print("Hmm: {:x}".format(dk))
|
||||
print(pow(ec,dk,n))
|
||||
print("Ending")
|
||||
sys.exit()
|
||||
nd=nodes[len(priors)-1]
|
||||
print("{:x}".format(nd.nodes[0].numconst))
|
||||
print("{:x}".format(nd.nodes[1].numconst))
|
||||
print("{:x}".format(nd.nodes[3].numconst))
|
||||
dfx2=nd.nodes[3].numconst
|
||||
rnd=nd.spow()
|
||||
print("rn {:x}".format(rnd.nodes[0].numconst))
|
||||
print("rn {:x}".format(rnd.nodes[1].numconst))
|
||||
dx2=rnd.nodes[3].numconst
|
||||
kn=3142033101700003260678755863863267700134374886049156296238778043258513471417667391237505300342672722921505586813412391537592394712287451780540489111338082979901966887630936873112829448279475520471433931949082770983040743133849146064289054900225131501940560027662491217132619227565578893295128589581903273904124801461070363532834633728769178636552784294153467969250254358604276515140477045217505629092433114246051368410587618590542410950189868285511930901887132942539241081579465767831350539339965000260768249119651905050152151634478714116343168832447694793716937575319879226685046081583200335708696821445923072794535
|
||||
print("rx {:x}".format(kn*65537%n))
|
||||
print("rrn {:x}".format(rnd.nodes[3].numconst))
|
||||
x=rnd.nodes[0].numconst
|
||||
fx=nd.nodes[0].numconst
|
||||
dfa=nd.nodes[1].numconst*modInverse(rnd.nodes[1].numconst,n)%n
|
||||
print("{:x}".format(dfa))
|
||||
dfq=dfa*x*modInverse(fx,n)%n
|
||||
print("{:x}".format(dfq))
|
||||
print("{:x}".format(pow(x,dfq,n)))
|
||||
#nd.nodes[0].numconst
|
||||
#res=nd.nodes[0].numconst*2
|
||||
#der=nd.nodes[1].numconst*2
|
||||
#dk=der*pow(res,65537,n)*modInverse(res,n)%n
|
||||
#kn=3142033101700003260678755863863267700134374886049156296238778043258513471417667391237505300342672722921505586813412391537592394712287451780540489111338082979901966887630936873112829448279475520471433931949082770983040743133849146064289054900225131501940560027662491217132619227565578893295128589581903273904124801461070363532834633728769178636552784294153467969250254358604276515140477045217505629092433114246051368410587618590542410950189868285511930901887132942539241081579465767831350539339965000260768249119651905050152151634478714116343168832447694793716937575319879226685046081583200335708696821445923072794535
|
||||
#print("kn: {:x}".format(kn))
|
||||
#print("{:x}".format(dk))
|
||||
#print("{:x}".format(priors[3]))
|
||||
#print("{:x}".format(pow(res,65537,n)))
|
||||
#print(res)
|
||||
for k in range(len(priors)):
|
||||
print("{}: {}".format(k,rels.get(priors[k],None)))
|
||||
sys.exit()
|
28598
log_parsing/relations.txt
Normal file
28598
log_parsing/relations.txt
Normal file
File diff suppressed because one or more lines are too long
30
manifest.json
Normal file
30
manifest.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Widevine Guesser",
|
||||
"short_name": "WidevineGuesser",
|
||||
"description": "Guesses at session key input and logs media keys from websites that use Widevine DRM",
|
||||
"version": "1.0.0",
|
||||
"permissions":
|
||||
[
|
||||
|
||||
],
|
||||
"icons":
|
||||
{
|
||||
|
||||
},
|
||||
"browser_action": {
|
||||
|
||||
},
|
||||
"content_scripts":
|
||||
[
|
||||
{
|
||||
"matches": ["https://*/*"],
|
||||
"js": ["content_script.js"],
|
||||
"css": [],
|
||||
"run_at": "document_start",
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
"content_security_policy": "script-src 'self' 'wasm-eval'; object-src 'self'",
|
||||
"web_accessible_resources": ["content_key_decryption.js", "eme_interception.js", "lib/*", "protobuf-generated/*","wasm/*"]
|
||||
}
|
BIN
memory_dumps/Hasmulret18016d24d_639.gz
Normal file
BIN
memory_dumps/Hasmulret18016d24d_639.gz
Normal file
Binary file not shown.
BIN
memory_dumps/Longstring_nearsha_621.gz
Normal file
BIN
memory_dumps/Longstring_nearsha_621.gz
Normal file
Binary file not shown.
BIN
memory_dumps/Longstring_postfun_623.gz
Normal file
BIN
memory_dumps/Longstring_postfun_623.gz
Normal file
Binary file not shown.
BIN
memory_dumps/Longstring_postsha_622.gz
Normal file
BIN
memory_dumps/Longstring_postsha_622.gz
Normal file
Binary file not shown.
BIN
memory_dumps/Longstringproc_620.gz
Normal file
BIN
memory_dumps/Longstringproc_620.gz
Normal file
Binary file not shown.
BIN
memory_dumps/Peri.gz
Normal file
BIN
memory_dumps/Peri.gz
Normal file
Binary file not shown.
BIN
memory_dumps/bollockrySnap.gz
Normal file
BIN
memory_dumps/bollockrySnap.gz
Normal file
Binary file not shown.
890
protobuf-generated/license_protocol.proto.js
Normal file
890
protobuf-generated/license_protocol.proto.js
Normal file
@ -0,0 +1,890 @@
|
||||
'use strict'; // code generated by pbf v3.2.1
|
||||
|
||||
var LicenseType = self.LicenseType = {
|
||||
"STREAMING": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"OFFLINE": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
var ProtocolVersion = self.ProtocolVersion = {
|
||||
"VERSION_2_0": {
|
||||
"value": 20,
|
||||
"options": {}
|
||||
},
|
||||
"VERSION_2_1": {
|
||||
"value": 21,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// LicenseIdentification ========================================
|
||||
|
||||
var LicenseIdentification = self.LicenseIdentification = {};
|
||||
|
||||
LicenseIdentification.read = function (pbf, end) {
|
||||
return pbf.readFields(LicenseIdentification._readField, {request_id: null, session_id: null, purchase_id: null, type: 0, version: 0, provider_session_token: null}, end);
|
||||
};
|
||||
LicenseIdentification._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.request_id = pbf.readBytes();
|
||||
else if (tag === 2) obj.session_id = pbf.readBytes();
|
||||
else if (tag === 3) obj.purchase_id = pbf.readBytes();
|
||||
else if (tag === 4) obj.type = pbf.readVarint();
|
||||
else if (tag === 5) obj.version = pbf.readVarint(true);
|
||||
else if (tag === 6) obj.provider_session_token = pbf.readBytes();
|
||||
};
|
||||
LicenseIdentification.write = function (obj, pbf) {
|
||||
if (obj.request_id) pbf.writeBytesField(1, obj.request_id);
|
||||
if (obj.session_id) pbf.writeBytesField(2, obj.session_id);
|
||||
if (obj.purchase_id) pbf.writeBytesField(3, obj.purchase_id);
|
||||
if (obj.type) pbf.writeVarintField(4, obj.type);
|
||||
if (obj.version) pbf.writeVarintField(5, obj.version);
|
||||
if (obj.provider_session_token) pbf.writeBytesField(6, obj.provider_session_token);
|
||||
};
|
||||
|
||||
// License ========================================
|
||||
|
||||
var License = self.License = {};
|
||||
|
||||
License.read = function (pbf, end) {
|
||||
return pbf.readFields(License._readField, {id: null, policy: null, key: [], license_start_time: 0, remote_attestation_verified: false, provider_client_token: null}, end);
|
||||
};
|
||||
License._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.id = LicenseIdentification.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 2) obj.policy = License.Policy.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 3) obj.key.push(License.KeyContainer.read(pbf, pbf.readVarint() + pbf.pos));
|
||||
else if (tag === 4) obj.license_start_time = pbf.readVarint(true);
|
||||
else if (tag === 5) obj.remote_attestation_verified = pbf.readBoolean();
|
||||
else if (tag === 6) obj.provider_client_token = pbf.readBytes();
|
||||
};
|
||||
License.write = function (obj, pbf) {
|
||||
if (obj.id) pbf.writeMessage(1, LicenseIdentification.write, obj.id);
|
||||
if (obj.policy) pbf.writeMessage(2, License.Policy.write, obj.policy);
|
||||
if (obj.key) for (var i = 0; i < obj.key.length; i++) pbf.writeMessage(3, License.KeyContainer.write, obj.key[i]);
|
||||
if (obj.license_start_time) pbf.writeVarintField(4, obj.license_start_time);
|
||||
if (obj.remote_attestation_verified) pbf.writeBooleanField(5, obj.remote_attestation_verified);
|
||||
if (obj.provider_client_token) pbf.writeBytesField(6, obj.provider_client_token);
|
||||
};
|
||||
|
||||
// License.Policy ========================================
|
||||
|
||||
License.Policy = {};
|
||||
|
||||
License.Policy.read = function (pbf, end) {
|
||||
return pbf.readFields(License.Policy._readField, {can_play: false, can_persist: false, can_renew: false, rental_duration_seconds: 0, playback_duration_seconds: 0, license_duration_seconds: 0, renewal_recovery_duration_seconds: 0, renewal_server_url: "", renewal_delay_seconds: 0, renewal_retry_interval_seconds: 0, renew_with_usage: false, renew_with_client_id: false}, end);
|
||||
};
|
||||
License.Policy._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.can_play = pbf.readBoolean();
|
||||
else if (tag === 2) obj.can_persist = pbf.readBoolean();
|
||||
else if (tag === 3) obj.can_renew = pbf.readBoolean();
|
||||
else if (tag === 4) obj.rental_duration_seconds = pbf.readVarint(true);
|
||||
else if (tag === 5) obj.playback_duration_seconds = pbf.readVarint(true);
|
||||
else if (tag === 6) obj.license_duration_seconds = pbf.readVarint(true);
|
||||
else if (tag === 7) obj.renewal_recovery_duration_seconds = pbf.readVarint(true);
|
||||
else if (tag === 8) obj.renewal_server_url = pbf.readString();
|
||||
else if (tag === 9) obj.renewal_delay_seconds = pbf.readVarint(true);
|
||||
else if (tag === 10) obj.renewal_retry_interval_seconds = pbf.readVarint(true);
|
||||
else if (tag === 11) obj.renew_with_usage = pbf.readBoolean();
|
||||
else if (tag === 12) obj.renew_with_client_id = pbf.readBoolean();
|
||||
};
|
||||
License.Policy.write = function (obj, pbf) {
|
||||
if (obj.can_play) pbf.writeBooleanField(1, obj.can_play);
|
||||
if (obj.can_persist) pbf.writeBooleanField(2, obj.can_persist);
|
||||
if (obj.can_renew) pbf.writeBooleanField(3, obj.can_renew);
|
||||
if (obj.rental_duration_seconds) pbf.writeVarintField(4, obj.rental_duration_seconds);
|
||||
if (obj.playback_duration_seconds) pbf.writeVarintField(5, obj.playback_duration_seconds);
|
||||
if (obj.license_duration_seconds) pbf.writeVarintField(6, obj.license_duration_seconds);
|
||||
if (obj.renewal_recovery_duration_seconds) pbf.writeVarintField(7, obj.renewal_recovery_duration_seconds);
|
||||
if (obj.renewal_server_url) pbf.writeStringField(8, obj.renewal_server_url);
|
||||
if (obj.renewal_delay_seconds) pbf.writeVarintField(9, obj.renewal_delay_seconds);
|
||||
if (obj.renewal_retry_interval_seconds) pbf.writeVarintField(10, obj.renewal_retry_interval_seconds);
|
||||
if (obj.renew_with_usage) pbf.writeBooleanField(11, obj.renew_with_usage);
|
||||
if (obj.renew_with_client_id) pbf.writeBooleanField(12, obj.renew_with_client_id);
|
||||
};
|
||||
|
||||
// License.KeyContainer ========================================
|
||||
|
||||
License.KeyContainer = {};
|
||||
|
||||
License.KeyContainer.read = function (pbf, end) {
|
||||
return pbf.readFields(License.KeyContainer._readField, {id: null, iv: null, key: null, type: 0, level: {"value":1,"options":{}}, required_protection: null, requested_protection: null, key_control: null, operator_session_key_permissions: null, video_resolution_constraints: [], anti_rollback_usage_table: false}, end);
|
||||
};
|
||||
License.KeyContainer._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.id = pbf.readBytes();
|
||||
else if (tag === 2) obj.iv = pbf.readBytes();
|
||||
else if (tag === 3) obj.key = pbf.readBytes();
|
||||
else if (tag === 4) obj.type = pbf.readVarint();
|
||||
else if (tag === 5) obj.level = pbf.readVarint();
|
||||
else if (tag === 6) obj.required_protection = License.KeyContainer.OutputProtection.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 7) obj.requested_protection = License.KeyContainer.OutputProtection.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 8) obj.key_control = License.KeyContainer.KeyControl.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 9) obj.operator_session_key_permissions = License.KeyContainer.OperatorSessionKeyPermissions.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 10) obj.video_resolution_constraints.push(License.KeyContainer.VideoResolutionConstraint.read(pbf, pbf.readVarint() + pbf.pos));
|
||||
else if (tag === 11) obj.anti_rollback_usage_table = pbf.readBoolean();
|
||||
};
|
||||
License.KeyContainer.write = function (obj, pbf) {
|
||||
if (obj.id) pbf.writeBytesField(1, obj.id);
|
||||
if (obj.iv) pbf.writeBytesField(2, obj.iv);
|
||||
if (obj.key) pbf.writeBytesField(3, obj.key);
|
||||
if (obj.type) pbf.writeVarintField(4, obj.type);
|
||||
if (obj.level != undefined && obj.level !== {"value":1,"options":{}}) pbf.writeVarintField(5, obj.level);
|
||||
if (obj.required_protection) pbf.writeMessage(6, License.KeyContainer.OutputProtection.write, obj.required_protection);
|
||||
if (obj.requested_protection) pbf.writeMessage(7, License.KeyContainer.OutputProtection.write, obj.requested_protection);
|
||||
if (obj.key_control) pbf.writeMessage(8, License.KeyContainer.KeyControl.write, obj.key_control);
|
||||
if (obj.operator_session_key_permissions) pbf.writeMessage(9, License.KeyContainer.OperatorSessionKeyPermissions.write, obj.operator_session_key_permissions);
|
||||
if (obj.video_resolution_constraints) for (var i = 0; i < obj.video_resolution_constraints.length; i++) pbf.writeMessage(10, License.KeyContainer.VideoResolutionConstraint.write, obj.video_resolution_constraints[i]);
|
||||
if (obj.anti_rollback_usage_table) pbf.writeBooleanField(11, obj.anti_rollback_usage_table);
|
||||
};
|
||||
|
||||
License.KeyContainer.KeyType = {
|
||||
"SIGNING": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"CONTENT": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
},
|
||||
"KEY_CONTROL": {
|
||||
"value": 3,
|
||||
"options": {}
|
||||
},
|
||||
"OPERATOR_SESSION": {
|
||||
"value": 4,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
License.KeyContainer.SecurityLevel = {
|
||||
"SW_SECURE_CRYPTO": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"SW_SECURE_DECODE": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
},
|
||||
"HW_SECURE_CRYPTO": {
|
||||
"value": 3,
|
||||
"options": {}
|
||||
},
|
||||
"HW_SECURE_DECODE": {
|
||||
"value": 4,
|
||||
"options": {}
|
||||
},
|
||||
"HW_SECURE_ALL": {
|
||||
"value": 5,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// License.KeyContainer.KeyControl ========================================
|
||||
|
||||
License.KeyContainer.KeyControl = {};
|
||||
|
||||
License.KeyContainer.KeyControl.read = function (pbf, end) {
|
||||
return pbf.readFields(License.KeyContainer.KeyControl._readField, {key_control_block: null, iv: null}, end);
|
||||
};
|
||||
License.KeyContainer.KeyControl._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.key_control_block = pbf.readBytes();
|
||||
else if (tag === 2) obj.iv = pbf.readBytes();
|
||||
};
|
||||
License.KeyContainer.KeyControl.write = function (obj, pbf) {
|
||||
if (obj.key_control_block) pbf.writeBytesField(1, obj.key_control_block);
|
||||
if (obj.iv) pbf.writeBytesField(2, obj.iv);
|
||||
};
|
||||
|
||||
// License.KeyContainer.OutputProtection ========================================
|
||||
|
||||
License.KeyContainer.OutputProtection = {};
|
||||
|
||||
License.KeyContainer.OutputProtection.read = function (pbf, end) {
|
||||
return pbf.readFields(License.KeyContainer.OutputProtection._readField, {hdcp: {"value":0,"options":{}}, cgms_flags: {"value":42,"options":{}}}, end);
|
||||
};
|
||||
License.KeyContainer.OutputProtection._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.hdcp = pbf.readVarint();
|
||||
else if (tag === 2) obj.cgms_flags = pbf.readVarint();
|
||||
};
|
||||
License.KeyContainer.OutputProtection.write = function (obj, pbf) {
|
||||
if (obj.hdcp != undefined && obj.hdcp !== {"value":0,"options":{}}) pbf.writeVarintField(1, obj.hdcp);
|
||||
if (obj.cgms_flags != undefined && obj.cgms_flags !== {"value":42,"options":{}}) pbf.writeVarintField(2, obj.cgms_flags);
|
||||
};
|
||||
|
||||
License.KeyContainer.OutputProtection.HDCP = {
|
||||
"HDCP_NONE": {
|
||||
"value": 0,
|
||||
"options": {}
|
||||
},
|
||||
"HDCP_V1": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"HDCP_V2": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
},
|
||||
"HDCP_V2_1": {
|
||||
"value": 3,
|
||||
"options": {}
|
||||
},
|
||||
"HDCP_V2_2": {
|
||||
"value": 4,
|
||||
"options": {}
|
||||
},
|
||||
"HDCP_NO_DIGITAL_OUTPUT": {
|
||||
"value": 255,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
License.KeyContainer.OutputProtection.CGMS = {
|
||||
"CGMS_NONE": {
|
||||
"value": 42,
|
||||
"options": {}
|
||||
},
|
||||
"COPY_FREE": {
|
||||
"value": 0,
|
||||
"options": {}
|
||||
},
|
||||
"COPY_ONCE": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
},
|
||||
"COPY_NEVER": {
|
||||
"value": 3,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// License.KeyContainer.VideoResolutionConstraint ========================================
|
||||
|
||||
License.KeyContainer.VideoResolutionConstraint = {};
|
||||
|
||||
License.KeyContainer.VideoResolutionConstraint.read = function (pbf, end) {
|
||||
return pbf.readFields(License.KeyContainer.VideoResolutionConstraint._readField, {min_resolution_pixels: 0, max_resolution_pixels: 0, required_protection: null}, end);
|
||||
};
|
||||
License.KeyContainer.VideoResolutionConstraint._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.min_resolution_pixels = pbf.readVarint();
|
||||
else if (tag === 2) obj.max_resolution_pixels = pbf.readVarint();
|
||||
else if (tag === 3) obj.required_protection = License.KeyContainer.OutputProtection.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
};
|
||||
License.KeyContainer.VideoResolutionConstraint.write = function (obj, pbf) {
|
||||
if (obj.min_resolution_pixels) pbf.writeVarintField(1, obj.min_resolution_pixels);
|
||||
if (obj.max_resolution_pixels) pbf.writeVarintField(2, obj.max_resolution_pixels);
|
||||
if (obj.required_protection) pbf.writeMessage(3, License.KeyContainer.OutputProtection.write, obj.required_protection);
|
||||
};
|
||||
|
||||
// License.KeyContainer.OperatorSessionKeyPermissions ========================================
|
||||
|
||||
License.KeyContainer.OperatorSessionKeyPermissions = {};
|
||||
|
||||
License.KeyContainer.OperatorSessionKeyPermissions.read = function (pbf, end) {
|
||||
return pbf.readFields(License.KeyContainer.OperatorSessionKeyPermissions._readField, {allow_encrypt: false, allow_decrypt: false, allow_sign: false, allow_signature_verify: false}, end);
|
||||
};
|
||||
License.KeyContainer.OperatorSessionKeyPermissions._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.allow_encrypt = pbf.readBoolean();
|
||||
else if (tag === 2) obj.allow_decrypt = pbf.readBoolean();
|
||||
else if (tag === 3) obj.allow_sign = pbf.readBoolean();
|
||||
else if (tag === 4) obj.allow_signature_verify = pbf.readBoolean();
|
||||
};
|
||||
License.KeyContainer.OperatorSessionKeyPermissions.write = function (obj, pbf) {
|
||||
if (obj.allow_encrypt) pbf.writeBooleanField(1, obj.allow_encrypt);
|
||||
if (obj.allow_decrypt) pbf.writeBooleanField(2, obj.allow_decrypt);
|
||||
if (obj.allow_sign) pbf.writeBooleanField(3, obj.allow_sign);
|
||||
if (obj.allow_signature_verify) pbf.writeBooleanField(4, obj.allow_signature_verify);
|
||||
};
|
||||
|
||||
// LicenseRequest ========================================
|
||||
|
||||
var LicenseRequest = self.LicenseRequest = {};
|
||||
|
||||
LicenseRequest.read = function (pbf, end) {
|
||||
return pbf.readFields(LicenseRequest._readField, {client_id: null, content_id: null, type: 0, request_time: 0, key_control_nonce_deprecated: null, protocol_version: {"value":20,"options":{}}, key_control_nonce: 0, encrypted_client_id: null}, end);
|
||||
};
|
||||
LicenseRequest._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.client_id = ClientIdentification.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 2) obj.content_id = LicenseRequest.ContentIdentification.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 3) obj.type = pbf.readVarint();
|
||||
else if (tag === 4) obj.request_time = pbf.readVarint(true);
|
||||
else if (tag === 5) obj.key_control_nonce_deprecated = pbf.readBytes();
|
||||
else if (tag === 6) obj.protocol_version = pbf.readVarint();
|
||||
else if (tag === 7) obj.key_control_nonce = pbf.readVarint();
|
||||
else if (tag === 8) obj.encrypted_client_id = EncryptedClientIdentification.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
};
|
||||
LicenseRequest.write = function (obj, pbf) {
|
||||
if (obj.client_id) pbf.writeMessage(1, ClientIdentification.write, obj.client_id);
|
||||
if (obj.content_id) pbf.writeMessage(2, LicenseRequest.ContentIdentification.write, obj.content_id);
|
||||
if (obj.type) pbf.writeVarintField(3, obj.type);
|
||||
if (obj.request_time) pbf.writeVarintField(4, obj.request_time);
|
||||
if (obj.key_control_nonce_deprecated) pbf.writeBytesField(5, obj.key_control_nonce_deprecated);
|
||||
if (obj.protocol_version != undefined && obj.protocol_version !== {"value":20,"options":{}}) pbf.writeVarintField(6, obj.protocol_version);
|
||||
if (obj.key_control_nonce) pbf.writeVarintField(7, obj.key_control_nonce);
|
||||
if (obj.encrypted_client_id) pbf.writeMessage(8, EncryptedClientIdentification.write, obj.encrypted_client_id);
|
||||
};
|
||||
|
||||
LicenseRequest.RequestType = {
|
||||
"NEW": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"RENEWAL": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
},
|
||||
"RELEASE": {
|
||||
"value": 3,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// LicenseRequest.ContentIdentification ========================================
|
||||
|
||||
LicenseRequest.ContentIdentification = {};
|
||||
|
||||
LicenseRequest.ContentIdentification.read = function (pbf, end) {
|
||||
return pbf.readFields(LicenseRequest.ContentIdentification._readField, {cenc_id: null, webm_id: null, license: null}, end);
|
||||
};
|
||||
LicenseRequest.ContentIdentification._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.cenc_id = LicenseRequest.ContentIdentification.CENC.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 2) obj.webm_id = LicenseRequest.ContentIdentification.WebM.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 3) obj.license = LicenseRequest.ContentIdentification.ExistingLicense.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
};
|
||||
LicenseRequest.ContentIdentification.write = function (obj, pbf) {
|
||||
if (obj.cenc_id) pbf.writeMessage(1, LicenseRequest.ContentIdentification.CENC.write, obj.cenc_id);
|
||||
if (obj.webm_id) pbf.writeMessage(2, LicenseRequest.ContentIdentification.WebM.write, obj.webm_id);
|
||||
if (obj.license) pbf.writeMessage(3, LicenseRequest.ContentIdentification.ExistingLicense.write, obj.license);
|
||||
};
|
||||
|
||||
// LicenseRequest.ContentIdentification.CENC ========================================
|
||||
|
||||
LicenseRequest.ContentIdentification.CENC = {};
|
||||
|
||||
LicenseRequest.ContentIdentification.CENC.read = function (pbf, end) {
|
||||
return pbf.readFields(LicenseRequest.ContentIdentification.CENC._readField, {pssh: [], license_type: 0, request_id: null}, end);
|
||||
};
|
||||
LicenseRequest.ContentIdentification.CENC._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.pssh.push(pbf.readBytes());
|
||||
else if (tag === 2) obj.license_type = pbf.readVarint();
|
||||
else if (tag === 3) obj.request_id = pbf.readBytes();
|
||||
};
|
||||
LicenseRequest.ContentIdentification.CENC.write = function (obj, pbf) {
|
||||
if (obj.pssh) for (var i = 0; i < obj.pssh.length; i++) pbf.writeBytesField(1, obj.pssh[i]);
|
||||
if (obj.license_type) pbf.writeVarintField(2, obj.license_type);
|
||||
if (obj.request_id) pbf.writeBytesField(3, obj.request_id);
|
||||
};
|
||||
|
||||
// LicenseRequest.ContentIdentification.WebM ========================================
|
||||
|
||||
LicenseRequest.ContentIdentification.WebM = {};
|
||||
|
||||
LicenseRequest.ContentIdentification.WebM.read = function (pbf, end) {
|
||||
return pbf.readFields(LicenseRequest.ContentIdentification.WebM._readField, {header: null, license_type: 0, request_id: null}, end);
|
||||
};
|
||||
LicenseRequest.ContentIdentification.WebM._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.header = pbf.readBytes();
|
||||
else if (tag === 2) obj.license_type = pbf.readVarint();
|
||||
else if (tag === 3) obj.request_id = pbf.readBytes();
|
||||
};
|
||||
LicenseRequest.ContentIdentification.WebM.write = function (obj, pbf) {
|
||||
if (obj.header) pbf.writeBytesField(1, obj.header);
|
||||
if (obj.license_type) pbf.writeVarintField(2, obj.license_type);
|
||||
if (obj.request_id) pbf.writeBytesField(3, obj.request_id);
|
||||
};
|
||||
|
||||
// LicenseRequest.ContentIdentification.ExistingLicense ========================================
|
||||
|
||||
LicenseRequest.ContentIdentification.ExistingLicense = {};
|
||||
|
||||
LicenseRequest.ContentIdentification.ExistingLicense.read = function (pbf, end) {
|
||||
return pbf.readFields(LicenseRequest.ContentIdentification.ExistingLicense._readField, {license_id: null, seconds_since_started: 0, seconds_since_last_played: 0, session_usage_table_entry: null}, end);
|
||||
};
|
||||
LicenseRequest.ContentIdentification.ExistingLicense._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.license_id = LicenseIdentification.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 2) obj.seconds_since_started = pbf.readVarint(true);
|
||||
else if (tag === 3) obj.seconds_since_last_played = pbf.readVarint(true);
|
||||
else if (tag === 4) obj.session_usage_table_entry = pbf.readBytes();
|
||||
};
|
||||
LicenseRequest.ContentIdentification.ExistingLicense.write = function (obj, pbf) {
|
||||
if (obj.license_id) pbf.writeMessage(1, LicenseIdentification.write, obj.license_id);
|
||||
if (obj.seconds_since_started) pbf.writeVarintField(2, obj.seconds_since_started);
|
||||
if (obj.seconds_since_last_played) pbf.writeVarintField(3, obj.seconds_since_last_played);
|
||||
if (obj.session_usage_table_entry) pbf.writeBytesField(4, obj.session_usage_table_entry);
|
||||
};
|
||||
|
||||
// LicenseError ========================================
|
||||
|
||||
var LicenseError = self.LicenseError = {};
|
||||
|
||||
LicenseError.read = function (pbf, end) {
|
||||
return pbf.readFields(LicenseError._readField, {error_code: 0}, end);
|
||||
};
|
||||
LicenseError._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.error_code = pbf.readVarint();
|
||||
};
|
||||
LicenseError.write = function (obj, pbf) {
|
||||
if (obj.error_code) pbf.writeVarintField(1, obj.error_code);
|
||||
};
|
||||
|
||||
LicenseError.Error = {
|
||||
"INVALID_DEVICE_CERTIFICATE": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"REVOKED_DEVICE_CERTIFICATE": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
},
|
||||
"SERVICE_UNAVAILABLE": {
|
||||
"value": 3,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// RemoteAttestation ========================================
|
||||
|
||||
var RemoteAttestation = self.RemoteAttestation = {};
|
||||
|
||||
RemoteAttestation.read = function (pbf, end) {
|
||||
return pbf.readFields(RemoteAttestation._readField, {certificate: null, salt: null, signature: null}, end);
|
||||
};
|
||||
RemoteAttestation._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.certificate = EncryptedClientIdentification.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 2) obj.salt = pbf.readBytes();
|
||||
else if (tag === 3) obj.signature = pbf.readBytes();
|
||||
};
|
||||
RemoteAttestation.write = function (obj, pbf) {
|
||||
if (obj.certificate) pbf.writeMessage(1, EncryptedClientIdentification.write, obj.certificate);
|
||||
if (obj.salt) pbf.writeBytesField(2, obj.salt);
|
||||
if (obj.signature) pbf.writeBytesField(3, obj.signature);
|
||||
};
|
||||
|
||||
// SignedMessage ========================================
|
||||
|
||||
var SignedMessage = self.SignedMessage = {};
|
||||
|
||||
SignedMessage.read = function (pbf, end) {
|
||||
return pbf.readFields(SignedMessage._readField, {type: 0, msg: null, signature: null, session_key: null, remote_attestation: null}, end);
|
||||
};
|
||||
SignedMessage._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.type = pbf.readVarint();
|
||||
else if (tag === 2) obj.msg = pbf.readBytes();
|
||||
else if (tag === 3) obj.signature = pbf.readBytes();
|
||||
else if (tag === 4) obj.session_key = pbf.readBytes();
|
||||
else if (tag === 5) obj.remote_attestation = RemoteAttestation.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
};
|
||||
SignedMessage.write = function (obj, pbf) {
|
||||
if (obj.type) pbf.writeVarintField(1, obj.type);
|
||||
if (obj.msg) pbf.writeBytesField(2, obj.msg);
|
||||
if (obj.signature) pbf.writeBytesField(3, obj.signature);
|
||||
if (obj.session_key) pbf.writeBytesField(4, obj.session_key);
|
||||
if (obj.remote_attestation) pbf.writeMessage(5, RemoteAttestation.write, obj.remote_attestation);
|
||||
};
|
||||
|
||||
SignedMessage.MessageType = {
|
||||
"LICENSE_REQUEST": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"LICENSE": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
},
|
||||
"ERROR_RESPONSE": {
|
||||
"value": 3,
|
||||
"options": {}
|
||||
},
|
||||
"SERVICE_CERTIFICATE_REQUEST": {
|
||||
"value": 4,
|
||||
"options": {}
|
||||
},
|
||||
"SERVICE_CERTIFICATE": {
|
||||
"value": 5,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// ProvisioningOptions ========================================
|
||||
|
||||
var ProvisioningOptions = self.ProvisioningOptions = {};
|
||||
|
||||
ProvisioningOptions.read = function (pbf, end) {
|
||||
return pbf.readFields(ProvisioningOptions._readField, {certificate_type: 0, certificate_authority: ""}, end);
|
||||
};
|
||||
ProvisioningOptions._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.certificate_type = pbf.readVarint();
|
||||
else if (tag === 2) obj.certificate_authority = pbf.readString();
|
||||
};
|
||||
ProvisioningOptions.write = function (obj, pbf) {
|
||||
if (obj.certificate_type) pbf.writeVarintField(1, obj.certificate_type);
|
||||
if (obj.certificate_authority) pbf.writeStringField(2, obj.certificate_authority);
|
||||
};
|
||||
|
||||
ProvisioningOptions.CertificateType = {
|
||||
"WIDEVINE_DRM": {
|
||||
"value": 0,
|
||||
"options": {}
|
||||
},
|
||||
"X509": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// ProvisioningRequest ========================================
|
||||
|
||||
var ProvisioningRequest = self.ProvisioningRequest = {};
|
||||
|
||||
ProvisioningRequest.read = function (pbf, end) {
|
||||
return pbf.readFields(ProvisioningRequest._readField, {client_id: null, nonce: null, options: null, stable_id: null}, end);
|
||||
};
|
||||
ProvisioningRequest._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.client_id = ClientIdentification.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 2) obj.nonce = pbf.readBytes();
|
||||
else if (tag === 3) obj.options = ProvisioningOptions.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
else if (tag === 4) obj.stable_id = pbf.readBytes();
|
||||
};
|
||||
ProvisioningRequest.write = function (obj, pbf) {
|
||||
if (obj.client_id) pbf.writeMessage(1, ClientIdentification.write, obj.client_id);
|
||||
if (obj.nonce) pbf.writeBytesField(2, obj.nonce);
|
||||
if (obj.options) pbf.writeMessage(3, ProvisioningOptions.write, obj.options);
|
||||
if (obj.stable_id) pbf.writeBytesField(4, obj.stable_id);
|
||||
};
|
||||
|
||||
// ProvisioningResponse ========================================
|
||||
|
||||
var ProvisioningResponse = self.ProvisioningResponse = {};
|
||||
|
||||
ProvisioningResponse.read = function (pbf, end) {
|
||||
return pbf.readFields(ProvisioningResponse._readField, {device_rsa_key: null, device_rsa_key_iv: null, device_certificate: null, nonce: null}, end);
|
||||
};
|
||||
ProvisioningResponse._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.device_rsa_key = pbf.readBytes();
|
||||
else if (tag === 2) obj.device_rsa_key_iv = pbf.readBytes();
|
||||
else if (tag === 3) obj.device_certificate = pbf.readBytes();
|
||||
else if (tag === 4) obj.nonce = pbf.readBytes();
|
||||
};
|
||||
ProvisioningResponse.write = function (obj, pbf) {
|
||||
if (obj.device_rsa_key) pbf.writeBytesField(1, obj.device_rsa_key);
|
||||
if (obj.device_rsa_key_iv) pbf.writeBytesField(2, obj.device_rsa_key_iv);
|
||||
if (obj.device_certificate) pbf.writeBytesField(3, obj.device_certificate);
|
||||
if (obj.nonce) pbf.writeBytesField(4, obj.nonce);
|
||||
};
|
||||
|
||||
// SignedProvisioningMessage ========================================
|
||||
|
||||
var SignedProvisioningMessage = self.SignedProvisioningMessage = {};
|
||||
|
||||
SignedProvisioningMessage.read = function (pbf, end) {
|
||||
return pbf.readFields(SignedProvisioningMessage._readField, {message: null, signature: null}, end);
|
||||
};
|
||||
SignedProvisioningMessage._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.message = pbf.readBytes();
|
||||
else if (tag === 2) obj.signature = pbf.readBytes();
|
||||
};
|
||||
SignedProvisioningMessage.write = function (obj, pbf) {
|
||||
if (obj.message) pbf.writeBytesField(1, obj.message);
|
||||
if (obj.signature) pbf.writeBytesField(2, obj.signature);
|
||||
};
|
||||
|
||||
// ClientIdentification ========================================
|
||||
|
||||
var ClientIdentification = self.ClientIdentification = {};
|
||||
|
||||
ClientIdentification.read = function (pbf, end) {
|
||||
return pbf.readFields(ClientIdentification._readField, {type: {"value":0,"options":{}}, token: null, client_info: [], provider_client_token: null, license_counter: 0, client_capabilities: null}, end);
|
||||
};
|
||||
ClientIdentification._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.type = pbf.readVarint();
|
||||
else if (tag === 2) obj.token = pbf.readBytes();
|
||||
else if (tag === 3) obj.client_info.push(ClientIdentification.NameValue.read(pbf, pbf.readVarint() + pbf.pos));
|
||||
else if (tag === 4) obj.provider_client_token = pbf.readBytes();
|
||||
else if (tag === 5) obj.license_counter = pbf.readVarint();
|
||||
else if (tag === 6) obj.client_capabilities = ClientIdentification.ClientCapabilities.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
};
|
||||
ClientIdentification.write = function (obj, pbf) {
|
||||
if (obj.type != undefined && obj.type !== {"value":0,"options":{}}) pbf.writeVarintField(1, obj.type);
|
||||
if (obj.token) pbf.writeBytesField(2, obj.token);
|
||||
if (obj.client_info) for (var i = 0; i < obj.client_info.length; i++) pbf.writeMessage(3, ClientIdentification.NameValue.write, obj.client_info[i]);
|
||||
if (obj.provider_client_token) pbf.writeBytesField(4, obj.provider_client_token);
|
||||
if (obj.license_counter) pbf.writeVarintField(5, obj.license_counter);
|
||||
if (obj.client_capabilities) pbf.writeMessage(6, ClientIdentification.ClientCapabilities.write, obj.client_capabilities);
|
||||
};
|
||||
|
||||
ClientIdentification.TokenType = {
|
||||
"KEYBOX": {
|
||||
"value": 0,
|
||||
"options": {}
|
||||
},
|
||||
"DEVICE_CERTIFICATE": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"REMOTE_ATTESTATION_CERTIFICATE": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// ClientIdentification.NameValue ========================================
|
||||
|
||||
ClientIdentification.NameValue = {};
|
||||
|
||||
ClientIdentification.NameValue.read = function (pbf, end) {
|
||||
return pbf.readFields(ClientIdentification.NameValue._readField, {name: "", value: ""}, end);
|
||||
};
|
||||
ClientIdentification.NameValue._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.name = pbf.readString();
|
||||
else if (tag === 2) obj.value = pbf.readString();
|
||||
};
|
||||
ClientIdentification.NameValue.write = function (obj, pbf) {
|
||||
if (obj.name) pbf.writeStringField(1, obj.name);
|
||||
if (obj.value) pbf.writeStringField(2, obj.value);
|
||||
};
|
||||
|
||||
// ClientIdentification.ClientCapabilities ========================================
|
||||
|
||||
ClientIdentification.ClientCapabilities = {};
|
||||
|
||||
ClientIdentification.ClientCapabilities.read = function (pbf, end) {
|
||||
return pbf.readFields(ClientIdentification.ClientCapabilities._readField, {client_token: false, session_token: false, video_resolution_constraints: false, max_hdcp_version: {"value":0,"options":{}}, oem_crypto_api_version: 0, anti_rollback_usage_table: false}, end);
|
||||
};
|
||||
ClientIdentification.ClientCapabilities._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.client_token = pbf.readBoolean();
|
||||
else if (tag === 2) obj.session_token = pbf.readBoolean();
|
||||
else if (tag === 3) obj.video_resolution_constraints = pbf.readBoolean();
|
||||
else if (tag === 4) obj.max_hdcp_version = pbf.readVarint();
|
||||
else if (tag === 5) obj.oem_crypto_api_version = pbf.readVarint();
|
||||
else if (tag === 6) obj.anti_rollback_usage_table = pbf.readBoolean();
|
||||
};
|
||||
ClientIdentification.ClientCapabilities.write = function (obj, pbf) {
|
||||
if (obj.client_token) pbf.writeBooleanField(1, obj.client_token);
|
||||
if (obj.session_token) pbf.writeBooleanField(2, obj.session_token);
|
||||
if (obj.video_resolution_constraints) pbf.writeBooleanField(3, obj.video_resolution_constraints);
|
||||
if (obj.max_hdcp_version != undefined && obj.max_hdcp_version !== {"value":0,"options":{}}) pbf.writeVarintField(4, obj.max_hdcp_version);
|
||||
if (obj.oem_crypto_api_version) pbf.writeVarintField(5, obj.oem_crypto_api_version);
|
||||
if (obj.anti_rollback_usage_table) pbf.writeBooleanField(6, obj.anti_rollback_usage_table);
|
||||
};
|
||||
|
||||
ClientIdentification.ClientCapabilities.HdcpVersion = {
|
||||
"HDCP_NONE": {
|
||||
"value": 0,
|
||||
"options": {}
|
||||
},
|
||||
"HDCP_V1": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"HDCP_V2": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
},
|
||||
"HDCP_V2_1": {
|
||||
"value": 3,
|
||||
"options": {}
|
||||
},
|
||||
"HDCP_V2_2": {
|
||||
"value": 4,
|
||||
"options": {}
|
||||
},
|
||||
"HDCP_NO_DIGITAL_OUTPUT": {
|
||||
"value": 255,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// EncryptedClientIdentification ========================================
|
||||
|
||||
var EncryptedClientIdentification = self.EncryptedClientIdentification = {};
|
||||
|
||||
EncryptedClientIdentification.read = function (pbf, end) {
|
||||
return pbf.readFields(EncryptedClientIdentification._readField, {service_id: "", service_certificate_serial_number: null, encrypted_client_id: null, encrypted_client_id_iv: null, encrypted_privacy_key: null}, end);
|
||||
};
|
||||
EncryptedClientIdentification._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.service_id = pbf.readString();
|
||||
else if (tag === 2) obj.service_certificate_serial_number = pbf.readBytes();
|
||||
else if (tag === 3) obj.encrypted_client_id = pbf.readBytes();
|
||||
else if (tag === 4) obj.encrypted_client_id_iv = pbf.readBytes();
|
||||
else if (tag === 5) obj.encrypted_privacy_key = pbf.readBytes();
|
||||
};
|
||||
EncryptedClientIdentification.write = function (obj, pbf) {
|
||||
if (obj.service_id) pbf.writeStringField(1, obj.service_id);
|
||||
if (obj.service_certificate_serial_number) pbf.writeBytesField(2, obj.service_certificate_serial_number);
|
||||
if (obj.encrypted_client_id) pbf.writeBytesField(3, obj.encrypted_client_id);
|
||||
if (obj.encrypted_client_id_iv) pbf.writeBytesField(4, obj.encrypted_client_id_iv);
|
||||
if (obj.encrypted_privacy_key) pbf.writeBytesField(5, obj.encrypted_privacy_key);
|
||||
};
|
||||
|
||||
// DeviceCertificate ========================================
|
||||
|
||||
var DeviceCertificate = self.DeviceCertificate = {};
|
||||
|
||||
DeviceCertificate.read = function (pbf, end) {
|
||||
return pbf.readFields(DeviceCertificate._readField, {type: 0, serial_number: null, creation_time_seconds: 0, public_key: null, system_id: 0, test_device_deprecated: false, service_id: ""}, end);
|
||||
};
|
||||
DeviceCertificate._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.type = pbf.readVarint();
|
||||
else if (tag === 2) obj.serial_number = pbf.readBytes();
|
||||
else if (tag === 3) obj.creation_time_seconds = pbf.readVarint();
|
||||
else if (tag === 4) obj.public_key = pbf.readBytes();
|
||||
else if (tag === 5) obj.system_id = pbf.readVarint();
|
||||
else if (tag === 6) obj.test_device_deprecated = pbf.readBoolean();
|
||||
else if (tag === 7) obj.service_id = pbf.readString();
|
||||
};
|
||||
DeviceCertificate.write = function (obj, pbf) {
|
||||
if (obj.type) pbf.writeVarintField(1, obj.type);
|
||||
if (obj.serial_number) pbf.writeBytesField(2, obj.serial_number);
|
||||
if (obj.creation_time_seconds) pbf.writeVarintField(3, obj.creation_time_seconds);
|
||||
if (obj.public_key) pbf.writeBytesField(4, obj.public_key);
|
||||
if (obj.system_id) pbf.writeVarintField(5, obj.system_id);
|
||||
if (obj.test_device_deprecated) pbf.writeBooleanField(6, obj.test_device_deprecated);
|
||||
if (obj.service_id) pbf.writeStringField(7, obj.service_id);
|
||||
};
|
||||
|
||||
DeviceCertificate.CertificateType = {
|
||||
"ROOT": {
|
||||
"value": 0,
|
||||
"options": {}
|
||||
},
|
||||
"INTERMEDIATE": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"USER_DEVICE": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
},
|
||||
"SERVICE": {
|
||||
"value": 3,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// SignedDeviceCertificate ========================================
|
||||
|
||||
var SignedDeviceCertificate = self.SignedDeviceCertificate = {};
|
||||
|
||||
SignedDeviceCertificate.read = function (pbf, end) {
|
||||
return pbf.readFields(SignedDeviceCertificate._readField, {device_certificate: null, signature: null, signer: null}, end);
|
||||
};
|
||||
SignedDeviceCertificate._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.device_certificate = pbf.readBytes();
|
||||
else if (tag === 2) obj.signature = pbf.readBytes();
|
||||
else if (tag === 3) obj.signer = SignedDeviceCertificate.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
};
|
||||
SignedDeviceCertificate.write = function (obj, pbf) {
|
||||
if (obj.device_certificate) pbf.writeBytesField(1, obj.device_certificate);
|
||||
if (obj.signature) pbf.writeBytesField(2, obj.signature);
|
||||
if (obj.signer) pbf.writeMessage(3, SignedDeviceCertificate.write, obj.signer);
|
||||
};
|
||||
|
||||
// ProvisionedDeviceInfo ========================================
|
||||
|
||||
var ProvisionedDeviceInfo = self.ProvisionedDeviceInfo = {};
|
||||
|
||||
ProvisionedDeviceInfo.read = function (pbf, end) {
|
||||
return pbf.readFields(ProvisionedDeviceInfo._readField, {system_id: 0, soc: "", manufacturer: "", model: "", device_type: "", model_year: 0, security_level: {"value":0,"options":{}}, test_device: false}, end);
|
||||
};
|
||||
ProvisionedDeviceInfo._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.system_id = pbf.readVarint();
|
||||
else if (tag === 2) obj.soc = pbf.readString();
|
||||
else if (tag === 3) obj.manufacturer = pbf.readString();
|
||||
else if (tag === 4) obj.model = pbf.readString();
|
||||
else if (tag === 5) obj.device_type = pbf.readString();
|
||||
else if (tag === 6) obj.model_year = pbf.readVarint();
|
||||
else if (tag === 7) obj.security_level = pbf.readVarint();
|
||||
else if (tag === 8) obj.test_device = pbf.readBoolean();
|
||||
};
|
||||
ProvisionedDeviceInfo.write = function (obj, pbf) {
|
||||
if (obj.system_id) pbf.writeVarintField(1, obj.system_id);
|
||||
if (obj.soc) pbf.writeStringField(2, obj.soc);
|
||||
if (obj.manufacturer) pbf.writeStringField(3, obj.manufacturer);
|
||||
if (obj.model) pbf.writeStringField(4, obj.model);
|
||||
if (obj.device_type) pbf.writeStringField(5, obj.device_type);
|
||||
if (obj.model_year) pbf.writeVarintField(6, obj.model_year);
|
||||
if (obj.security_level != undefined && obj.security_level !== {"value":0,"options":{}}) pbf.writeVarintField(7, obj.security_level);
|
||||
if (obj.test_device) pbf.writeBooleanField(8, obj.test_device);
|
||||
};
|
||||
|
||||
ProvisionedDeviceInfo.WvSecurityLevel = {
|
||||
"LEVEL_UNSPECIFIED": {
|
||||
"value": 0,
|
||||
"options": {}
|
||||
},
|
||||
"LEVEL_1": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
},
|
||||
"LEVEL_2": {
|
||||
"value": 2,
|
||||
"options": {}
|
||||
},
|
||||
"LEVEL_3": {
|
||||
"value": 3,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// DeviceCertificateStatus ========================================
|
||||
|
||||
var DeviceCertificateStatus = self.DeviceCertificateStatus = {};
|
||||
|
||||
DeviceCertificateStatus.read = function (pbf, end) {
|
||||
return pbf.readFields(DeviceCertificateStatus._readField, {serial_number: null, status: {"value":0,"options":{}}, device_info: null}, end);
|
||||
};
|
||||
DeviceCertificateStatus._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.serial_number = pbf.readBytes();
|
||||
else if (tag === 2) obj.status = pbf.readVarint();
|
||||
else if (tag === 4) obj.device_info = ProvisionedDeviceInfo.read(pbf, pbf.readVarint() + pbf.pos);
|
||||
};
|
||||
DeviceCertificateStatus.write = function (obj, pbf) {
|
||||
if (obj.serial_number) pbf.writeBytesField(1, obj.serial_number);
|
||||
if (obj.status != undefined && obj.status !== {"value":0,"options":{}}) pbf.writeVarintField(2, obj.status);
|
||||
if (obj.device_info) pbf.writeMessage(4, ProvisionedDeviceInfo.write, obj.device_info);
|
||||
};
|
||||
|
||||
DeviceCertificateStatus.CertificateStatus = {
|
||||
"VALID": {
|
||||
"value": 0,
|
||||
"options": {}
|
||||
},
|
||||
"REVOKED": {
|
||||
"value": 1,
|
||||
"options": {}
|
||||
}
|
||||
};
|
||||
|
||||
// DeviceCertificateStatusList ========================================
|
||||
|
||||
var DeviceCertificateStatusList = self.DeviceCertificateStatusList = {};
|
||||
|
||||
DeviceCertificateStatusList.read = function (pbf, end) {
|
||||
return pbf.readFields(DeviceCertificateStatusList._readField, {creation_time_seconds: 0, certificate_status: []}, end);
|
||||
};
|
||||
DeviceCertificateStatusList._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.creation_time_seconds = pbf.readVarint();
|
||||
else if (tag === 2) obj.certificate_status.push(DeviceCertificateStatus.read(pbf, pbf.readVarint() + pbf.pos));
|
||||
};
|
||||
DeviceCertificateStatusList.write = function (obj, pbf) {
|
||||
if (obj.creation_time_seconds) pbf.writeVarintField(1, obj.creation_time_seconds);
|
||||
if (obj.certificate_status) for (var i = 0; i < obj.certificate_status.length; i++) pbf.writeMessage(2, DeviceCertificateStatus.write, obj.certificate_status[i]);
|
||||
};
|
||||
|
||||
// SignedCertificateStatusList ========================================
|
||||
|
||||
var SignedCertificateStatusList = self.SignedCertificateStatusList = {};
|
||||
|
||||
SignedCertificateStatusList.read = function (pbf, end) {
|
||||
return pbf.readFields(SignedCertificateStatusList._readField, {certificate_status_list: null, signature: null}, end);
|
||||
};
|
||||
SignedCertificateStatusList._readField = function (tag, obj, pbf) {
|
||||
if (tag === 1) obj.certificate_status_list = pbf.readBytes();
|
||||
else if (tag === 2) obj.signature = pbf.readBytes();
|
||||
};
|
||||
SignedCertificateStatusList.write = function (obj, pbf) {
|
||||
if (obj.certificate_status_list) pbf.writeBytesField(1, obj.certificate_status_list);
|
||||
if (obj.signature) pbf.writeBytesField(2, obj.signature);
|
||||
};
|
21
wasm/wasm_gsr.js
Normal file
21
wasm/wasm_gsr.js
Normal file
File diff suppressed because one or more lines are too long
BIN
wasm/wasm_gsr.wasm
Normal file
BIN
wasm/wasm_gsr.wasm
Normal file
Binary file not shown.
345
wasm_src/algebra.cpp
Normal file
345
wasm_src/algebra.cpp
Normal file
@ -0,0 +1,345 @@
|
||||
// algebra.cpp - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
#ifndef CRYPTOPP_ALGEBRA_CPP // SunCC workaround: compiler could cause this file to be included twice
|
||||
#define CRYPTOPP_ALGEBRA_CPP
|
||||
|
||||
#include "algebra.h"
|
||||
#include "integer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
template <class T> const T& AbstractGroup<T>::Double(const Element &a) const
|
||||
{
|
||||
return this->Add(a, a);
|
||||
}
|
||||
|
||||
template <class T> const T& AbstractGroup<T>::Subtract(const Element &a, const Element &b) const
|
||||
{
|
||||
// make copy of a in case Inverse() overwrites it
|
||||
Element a1(a);
|
||||
return this->Add(a1, Inverse(b));
|
||||
}
|
||||
|
||||
template <class T> T& AbstractGroup<T>::Accumulate(Element &a, const Element &b) const
|
||||
{
|
||||
return a = this->Add(a, b);
|
||||
}
|
||||
|
||||
template <class T> T& AbstractGroup<T>::Reduce(Element &a, const Element &b) const
|
||||
{
|
||||
return a = this->Subtract(a, b);
|
||||
}
|
||||
|
||||
template <class T> const T& AbstractRing<T>::Square(const Element &a) const
|
||||
{
|
||||
return this->Multiply(a, a);
|
||||
}
|
||||
|
||||
template <class T> const T& AbstractRing<T>::Divide(const Element &a, const Element &b) const
|
||||
{
|
||||
// make copy of a in case MultiplicativeInverse() overwrites it
|
||||
Element a1(a);
|
||||
return this->Multiply(a1, this->MultiplicativeInverse(b));
|
||||
}
|
||||
|
||||
template <class T> const T& AbstractEuclideanDomain<T>::Mod(const Element &a, const Element &b) const
|
||||
{
|
||||
Element q;
|
||||
this->DivisionAlgorithm(result, q, a, b);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T> const T& AbstractEuclideanDomain<T>::Gcd(const Element &a, const Element &b) const
|
||||
{
|
||||
Element g[3]={b, a};
|
||||
unsigned int i0=0, i1=1, i2=2;
|
||||
|
||||
while (!this->Equal(g[i1], this->Identity()))
|
||||
{
|
||||
g[i2] = this->Mod(g[i0], g[i1]);
|
||||
unsigned int t = i0; i0 = i1; i1 = i2; i2 = t;
|
||||
}
|
||||
|
||||
return result = g[i0];
|
||||
}
|
||||
|
||||
template <class T> const typename QuotientRing<T>::Element& QuotientRing<T>::MultiplicativeInverse(const Element &a) const
|
||||
{
|
||||
Element g[3]={m_modulus, a};
|
||||
Element v[3]={m_domain.Identity(), m_domain.MultiplicativeIdentity()};
|
||||
Element y;
|
||||
unsigned int i0=0, i1=1, i2=2;
|
||||
|
||||
while (!this->Equal(g[i1], this->Identity()))
|
||||
{
|
||||
// y = g[i0] / g[i1];
|
||||
// g[i2] = g[i0] % g[i1];
|
||||
m_domain.DivisionAlgorithm(g[i2], y, g[i0], g[i1]);
|
||||
// v[i2] = v[i0] - (v[i1] * y);
|
||||
v[i2] = m_domain.Subtract(v[i0], m_domain.Multiply(v[i1], y));
|
||||
unsigned int t = i0; i0 = i1; i1 = i2; i2 = t;
|
||||
}
|
||||
|
||||
return m_domain.IsUnit(g[i0]) ? m_domain.Divide(v[i0], g[i0]) : m_domain.Identity();
|
||||
}
|
||||
|
||||
template <class T> T AbstractGroup<T>::ScalarMultiply(const Element &base, const Integer &exponent) const
|
||||
{
|
||||
Element result;
|
||||
this->SimultaneousMultiply(&result, base, &exponent, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T> T AbstractGroup<T>::CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const
|
||||
{
|
||||
const unsigned expLen = STDMAX(e1.BitCount(), e2.BitCount());
|
||||
if (expLen==0)
|
||||
return this->Identity();
|
||||
|
||||
const unsigned w = (expLen <= 46 ? 1 : (expLen <= 260 ? 2 : 3));
|
||||
const unsigned tableSize = 1<<w;
|
||||
std::vector<Element> powerTable(tableSize << w);
|
||||
|
||||
powerTable[1] = x;
|
||||
powerTable[tableSize] = y;
|
||||
if (w==1)
|
||||
powerTable[3] = this->Add(x,y);
|
||||
else
|
||||
{
|
||||
powerTable[2] = this->Double(x);
|
||||
powerTable[2*tableSize] = this->Double(y);
|
||||
|
||||
unsigned i, j;
|
||||
|
||||
for (i=3; i<tableSize; i+=2)
|
||||
powerTable[i] = Add(powerTable[i-2], powerTable[2]);
|
||||
for (i=1; i<tableSize; i+=2)
|
||||
for (j=i+tableSize; j<(tableSize<<w); j+=tableSize)
|
||||
powerTable[j] = Add(powerTable[j-tableSize], y);
|
||||
|
||||
for (i=3*tableSize; i<(tableSize<<w); i+=2*tableSize)
|
||||
powerTable[i] = Add(powerTable[i-2*tableSize], powerTable[2*tableSize]);
|
||||
for (i=tableSize; i<(tableSize<<w); i+=2*tableSize)
|
||||
for (j=i+2; j<i+tableSize; j+=2)
|
||||
powerTable[j] = Add(powerTable[j-1], x);
|
||||
}
|
||||
|
||||
Element result;
|
||||
unsigned power1 = 0, power2 = 0, prevPosition = expLen-1;
|
||||
bool firstTime = true;
|
||||
|
||||
for (int i = expLen-1; i>=0; i--)
|
||||
{
|
||||
power1 = 2*power1 + e1.GetBit(i);
|
||||
power2 = 2*power2 + e2.GetBit(i);
|
||||
|
||||
if (i==0 || 2*power1 >= tableSize || 2*power2 >= tableSize)
|
||||
{
|
||||
unsigned squaresBefore = prevPosition-i;
|
||||
unsigned squaresAfter = 0;
|
||||
prevPosition = i;
|
||||
while ((power1 || power2) && power1%2 == 0 && power2%2==0)
|
||||
{
|
||||
power1 /= 2;
|
||||
power2 /= 2;
|
||||
squaresBefore--;
|
||||
squaresAfter++;
|
||||
}
|
||||
if (firstTime)
|
||||
{
|
||||
result = powerTable[(power2<<w) + power1];
|
||||
firstTime = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (squaresBefore--)
|
||||
result = this->Double(result);
|
||||
if (power1 || power2)
|
||||
Accumulate(result, powerTable[(power2<<w) + power1]);
|
||||
}
|
||||
while (squaresAfter--)
|
||||
result = this->Double(result);
|
||||
power1 = power2 = 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Element, class Iterator> Element GeneralCascadeMultiplication(const AbstractGroup<Element> &group, Iterator begin, Iterator end)
|
||||
{
|
||||
if (end-begin == 1)
|
||||
return group.ScalarMultiply(begin->base, begin->exponent);
|
||||
else if (end-begin == 2)
|
||||
return group.CascadeScalarMultiply(begin->base, begin->exponent, (begin+1)->base, (begin+1)->exponent);
|
||||
else
|
||||
{
|
||||
Integer q, t;
|
||||
Iterator last = end;
|
||||
--last;
|
||||
|
||||
std::make_heap(begin, end);
|
||||
std::pop_heap(begin, end);
|
||||
|
||||
while (!!begin->exponent)
|
||||
{
|
||||
// last->exponent is largest exponent, begin->exponent is next largest
|
||||
t = last->exponent;
|
||||
Integer::Divide(last->exponent, q, t, begin->exponent);
|
||||
|
||||
if (q == Integer::One())
|
||||
group.Accumulate(begin->base, last->base); // avoid overhead of ScalarMultiply()
|
||||
else
|
||||
group.Accumulate(begin->base, group.ScalarMultiply(last->base, q));
|
||||
|
||||
std::push_heap(begin, end);
|
||||
std::pop_heap(begin, end);
|
||||
}
|
||||
|
||||
return group.ScalarMultiply(last->base, last->exponent);
|
||||
}
|
||||
}
|
||||
|
||||
struct WindowSlider
|
||||
{
|
||||
WindowSlider(const Integer &expIn, bool fastNegate, unsigned int windowSizeIn=0)
|
||||
: exp(expIn), windowModulus(Integer::One()), windowSize(windowSizeIn), windowBegin(0), expWindow(0)
|
||||
, fastNegate(fastNegate), negateNext(false), firstTime(true), finished(false)
|
||||
{
|
||||
if (windowSize == 0)
|
||||
{
|
||||
unsigned int expLen = exp.BitCount();
|
||||
windowSize = expLen <= 17 ? 1 : (expLen <= 24 ? 2 : (expLen <= 70 ? 3 : (expLen <= 197 ? 4 : (expLen <= 539 ? 5 : (expLen <= 1434 ? 6 : 7)))));
|
||||
}
|
||||
windowModulus <<= windowSize;
|
||||
}
|
||||
|
||||
void FindNextWindow()
|
||||
{
|
||||
unsigned int expLen = exp.WordCount() * WORD_BITS;
|
||||
unsigned int skipCount = firstTime ? 0 : windowSize;
|
||||
firstTime = false;
|
||||
while (!exp.GetBit(skipCount))
|
||||
{
|
||||
if (skipCount >= expLen)
|
||||
{
|
||||
finished = true;
|
||||
return;
|
||||
}
|
||||
skipCount++;
|
||||
}
|
||||
|
||||
exp >>= skipCount;
|
||||
windowBegin += skipCount;
|
||||
expWindow = word32(exp % (word(1) << windowSize));
|
||||
|
||||
if (fastNegate && exp.GetBit(windowSize))
|
||||
{
|
||||
negateNext = true;
|
||||
expWindow = (word32(1) << windowSize) - expWindow;
|
||||
exp += windowModulus;
|
||||
}
|
||||
else
|
||||
negateNext = false;
|
||||
}
|
||||
|
||||
Integer exp, windowModulus;
|
||||
unsigned int windowSize, windowBegin;
|
||||
word32 expWindow;
|
||||
bool fastNegate, negateNext, firstTime, finished;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void AbstractGroup<T>::SimultaneousMultiply(T *results, const T &base, const Integer *expBegin, unsigned int expCount) const
|
||||
{
|
||||
std::vector<std::vector<Element> > buckets(expCount);
|
||||
std::vector<WindowSlider> exponents;
|
||||
exponents.reserve(expCount);
|
||||
unsigned int i;
|
||||
|
||||
for (i=0; expBegin && i<expCount; i++)
|
||||
{
|
||||
CRYPTOPP_ASSERT(expBegin->NotNegative());
|
||||
exponents.push_back(WindowSlider(*expBegin++, InversionIsFast(), 0));
|
||||
exponents[i].FindNextWindow();
|
||||
buckets[i].resize(((size_t) 1) << (exponents[i].windowSize-1), Identity());
|
||||
}
|
||||
|
||||
unsigned int expBitPosition = 0;
|
||||
Element g = base;
|
||||
bool notDone = true;
|
||||
|
||||
while (notDone)
|
||||
{
|
||||
notDone = false;
|
||||
for (i=0; i<expCount; i++)
|
||||
{
|
||||
if (!exponents[i].finished && expBitPosition == exponents[i].windowBegin)
|
||||
{
|
||||
Element &bucket = buckets[i][exponents[i].expWindow/2];
|
||||
if (exponents[i].negateNext)
|
||||
Accumulate(bucket, Inverse(g));
|
||||
else
|
||||
Accumulate(bucket, g);
|
||||
exponents[i].FindNextWindow();
|
||||
}
|
||||
notDone = notDone || !exponents[i].finished;
|
||||
}
|
||||
|
||||
if (notDone)
|
||||
{
|
||||
g = Double(g);
|
||||
expBitPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<expCount; i++)
|
||||
{
|
||||
Element &r = *results++;
|
||||
r = buckets[i][buckets[i].size()-1];
|
||||
if (buckets[i].size() > 1)
|
||||
{
|
||||
for (int j = (int)buckets[i].size()-2; j >= 1; j--)
|
||||
{
|
||||
Accumulate(buckets[i][j], buckets[i][j+1]);
|
||||
Accumulate(r, buckets[i][j]);
|
||||
}
|
||||
Accumulate(buckets[i][0], buckets[i][1]);
|
||||
r = Add(Double(r), buckets[i][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> T AbstractRing<T>::Exponentiate(const Element &base, const Integer &exponent) const
|
||||
{
|
||||
Element result;
|
||||
SimultaneousExponentiate(&result, base, &exponent, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T> T AbstractRing<T>::CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const
|
||||
{
|
||||
return MultiplicativeGroup().AbstractGroup<T>::CascadeScalarMultiply(x, e1, y, e2);
|
||||
}
|
||||
|
||||
template <class Element, class Iterator> Element GeneralCascadeExponentiation(const AbstractRing<Element> &ring, Iterator begin, Iterator end)
|
||||
{
|
||||
return GeneralCascadeMultiplication<Element>(ring.MultiplicativeGroup(), begin, end);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AbstractRing<T>::SimultaneousExponentiate(T *results, const T &base, const Integer *exponents, unsigned int expCount) const
|
||||
{
|
||||
MultiplicativeGroup().AbstractGroup<T>::SimultaneousMultiply(results, base, exponents, expCount);
|
||||
}
|
||||
|
||||
template class AbstractGroup<Integer>;
|
||||
template class AbstractRing<Integer>;
|
||||
template class AbstractEuclideanDomain<Integer>;
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
453
wasm_src/algebra.h
Normal file
453
wasm_src/algebra.h
Normal file
@ -0,0 +1,453 @@
|
||||
// algebra.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file algebra.h
|
||||
/// \brief Classes for performing mathematics over different fields
|
||||
|
||||
#ifndef CRYPTOPP_ALGEBRA_H
|
||||
#define CRYPTOPP_ALGEBRA_H
|
||||
|
||||
#include "config.h"
|
||||
#include "integer.h"
|
||||
#include "misc.h"
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
class Integer;
|
||||
|
||||
/// \brief Abstract group
|
||||
/// \tparam T element class or type
|
||||
/// \details <tt>const Element&</tt> returned by member functions are references
|
||||
/// to internal data members. Since each object may have only
|
||||
/// one such data member for holding results, the following code
|
||||
/// will produce incorrect results:
|
||||
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
|
||||
/// But this should be fine:
|
||||
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
|
||||
template <class T> class CRYPTOPP_NO_VTABLE AbstractGroup
|
||||
{
|
||||
public:
|
||||
typedef T Element;
|
||||
|
||||
virtual ~AbstractGroup() {}
|
||||
|
||||
/// \brief Compare two elements for equality
|
||||
/// \param a first element
|
||||
/// \param b second element
|
||||
/// \return true if the elements are equal, false otherwise
|
||||
/// \details Equal() tests the elements for equality using <tt>a==b</tt>
|
||||
virtual bool Equal(const Element &a, const Element &b) const =0;
|
||||
|
||||
/// \brief Provides the Identity element
|
||||
/// \return the Identity element
|
||||
virtual const Element& Identity() const =0;
|
||||
|
||||
/// \brief Adds elements in the group
|
||||
/// \param a first element
|
||||
/// \param b second element
|
||||
/// \return the sum of <tt>a</tt> and <tt>b</tt>
|
||||
virtual const Element& Add(const Element &a, const Element &b) const =0;
|
||||
|
||||
/// \brief Inverts the element in the group
|
||||
/// \param a first element
|
||||
/// \return the inverse of the element
|
||||
virtual const Element& Inverse(const Element &a) const =0;
|
||||
|
||||
/// \brief Determine if inversion is fast
|
||||
/// \return true if inversion is fast, false otherwise
|
||||
virtual bool InversionIsFast() const {return false;}
|
||||
|
||||
/// \brief Doubles an element in the group
|
||||
/// \param a the element
|
||||
/// \return the element doubled
|
||||
virtual const Element& Double(const Element &a) const;
|
||||
|
||||
/// \brief Subtracts elements in the group
|
||||
/// \param a first element
|
||||
/// \param b second element
|
||||
/// \return the difference of <tt>a</tt> and <tt>b</tt>. The element <tt>a</tt> must provide a Subtract member function.
|
||||
virtual const Element& Subtract(const Element &a, const Element &b) const;
|
||||
|
||||
/// \brief TODO
|
||||
/// \param a first element
|
||||
/// \param b second element
|
||||
/// \return TODO
|
||||
virtual Element& Accumulate(Element &a, const Element &b) const;
|
||||
|
||||
/// \brief Reduces an element in the congruence class
|
||||
/// \param a element to reduce
|
||||
/// \param b the congruence class
|
||||
/// \return the reduced element
|
||||
virtual Element& Reduce(Element &a, const Element &b) const;
|
||||
|
||||
/// \brief Performs a scalar multiplication
|
||||
/// \param a multiplicand
|
||||
/// \param e multiplier
|
||||
/// \return the product
|
||||
virtual Element ScalarMultiply(const Element &a, const Integer &e) const;
|
||||
|
||||
/// \brief TODO
|
||||
/// \param x first multiplicand
|
||||
/// \param e1 the first multiplier
|
||||
/// \param y second multiplicand
|
||||
/// \param e2 the second multiplier
|
||||
/// \return TODO
|
||||
virtual Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const;
|
||||
|
||||
/// \brief Multiplies a base to multiple exponents in a group
|
||||
/// \param results an array of Elements
|
||||
/// \param base the base to raise to the exponents
|
||||
/// \param exponents an array of exponents
|
||||
/// \param exponentsCount the number of exponents in the array
|
||||
/// \details SimultaneousMultiply() multiplies the base to each exponent in the exponents array and stores the
|
||||
/// result at the respective position in the results array.
|
||||
/// \details SimultaneousMultiply() must be implemented in a derived class.
|
||||
/// \pre <tt>COUNTOF(results) == exponentsCount</tt>
|
||||
/// \pre <tt>COUNTOF(exponents) == exponentsCount</tt>
|
||||
virtual void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
|
||||
};
|
||||
|
||||
/// \brief Abstract ring
|
||||
/// \tparam T element class or type
|
||||
/// \details <tt>const Element&</tt> returned by member functions are references
|
||||
/// to internal data members. Since each object may have only
|
||||
/// one such data member for holding results, the following code
|
||||
/// will produce incorrect results:
|
||||
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
|
||||
/// But this should be fine:
|
||||
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
|
||||
template <class T> class CRYPTOPP_NO_VTABLE AbstractRing : public AbstractGroup<T>
|
||||
{
|
||||
public:
|
||||
typedef T Element;
|
||||
|
||||
/// \brief Construct an AbstractRing
|
||||
AbstractRing() {m_mg.m_pRing = this;}
|
||||
|
||||
/// \brief Copy construct an AbstractRing
|
||||
/// \param source other AbstractRing
|
||||
AbstractRing(const AbstractRing &source)
|
||||
{CRYPTOPP_UNUSED(source); m_mg.m_pRing = this;}
|
||||
|
||||
/// \brief Assign an AbstractRing
|
||||
/// \param source other AbstractRing
|
||||
AbstractRing& operator=(const AbstractRing &source)
|
||||
{CRYPTOPP_UNUSED(source); return *this;}
|
||||
|
||||
/// \brief Determines whether an element is a unit in the group
|
||||
/// \param a the element
|
||||
/// \return true if the element is a unit after reduction, false otherwise.
|
||||
virtual bool IsUnit(const Element &a) const =0;
|
||||
|
||||
/// \brief Retrieves the multiplicative identity
|
||||
/// \return the multiplicative identity
|
||||
virtual const Element& MultiplicativeIdentity() const =0;
|
||||
|
||||
/// \brief Multiplies elements in the group
|
||||
/// \param a the multiplicand
|
||||
/// \param b the multiplier
|
||||
/// \return the product of a and b
|
||||
virtual const Element& Multiply(const Element &a, const Element &b) const =0;
|
||||
|
||||
/// \brief Calculate the multiplicative inverse of an element in the group
|
||||
/// \param a the element
|
||||
virtual const Element& MultiplicativeInverse(const Element &a) const =0;
|
||||
|
||||
/// \brief Square an element in the group
|
||||
/// \param a the element
|
||||
/// \return the element squared
|
||||
virtual const Element& Square(const Element &a) const;
|
||||
|
||||
/// \brief Divides elements in the group
|
||||
/// \param a the dividend
|
||||
/// \param b the divisor
|
||||
/// \return the quotient
|
||||
virtual const Element& Divide(const Element &a, const Element &b) const;
|
||||
|
||||
/// \brief Raises a base to an exponent in the group
|
||||
/// \param a the base
|
||||
/// \param e the exponent
|
||||
/// \return the exponentiation
|
||||
virtual Element Exponentiate(const Element &a, const Integer &e) const;
|
||||
|
||||
/// \brief TODO
|
||||
/// \param x first element
|
||||
/// \param e1 first exponent
|
||||
/// \param y second element
|
||||
/// \param e2 second exponent
|
||||
/// \return TODO
|
||||
virtual Element CascadeExponentiate(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const;
|
||||
|
||||
/// \brief Exponentiates a base to multiple exponents in the Ring
|
||||
/// \param results an array of Elements
|
||||
/// \param base the base to raise to the exponents
|
||||
/// \param exponents an array of exponents
|
||||
/// \param exponentsCount the number of exponents in the array
|
||||
/// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the
|
||||
/// result at the respective position in the results array.
|
||||
/// \details SimultaneousExponentiate() must be implemented in a derived class.
|
||||
/// \pre <tt>COUNTOF(results) == exponentsCount</tt>
|
||||
/// \pre <tt>COUNTOF(exponents) == exponentsCount</tt>
|
||||
virtual void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
|
||||
|
||||
/// \brief Retrieves the multiplicative group
|
||||
/// \return the multiplicative group
|
||||
virtual const AbstractGroup<T>& MultiplicativeGroup() const
|
||||
{return m_mg;}
|
||||
|
||||
private:
|
||||
class MultiplicativeGroupT : public AbstractGroup<T>
|
||||
{
|
||||
public:
|
||||
const AbstractRing<T>& GetRing() const
|
||||
{return *m_pRing;}
|
||||
|
||||
bool Equal(const Element &a, const Element &b) const
|
||||
{return GetRing().Equal(a, b);}
|
||||
|
||||
const Element& Identity() const
|
||||
{return GetRing().MultiplicativeIdentity();}
|
||||
|
||||
const Element& Add(const Element &a, const Element &b) const
|
||||
{return GetRing().Multiply(a, b);}
|
||||
|
||||
Element& Accumulate(Element &a, const Element &b) const
|
||||
{return a = GetRing().Multiply(a, b);}
|
||||
|
||||
const Element& Inverse(const Element &a) const
|
||||
{return GetRing().MultiplicativeInverse(a);}
|
||||
|
||||
const Element& Subtract(const Element &a, const Element &b) const
|
||||
{return GetRing().Divide(a, b);}
|
||||
|
||||
Element& Reduce(Element &a, const Element &b) const
|
||||
{return a = GetRing().Divide(a, b);}
|
||||
|
||||
const Element& Double(const Element &a) const
|
||||
{return GetRing().Square(a);}
|
||||
|
||||
Element ScalarMultiply(const Element &a, const Integer &e) const
|
||||
{return GetRing().Exponentiate(a, e);}
|
||||
|
||||
Element CascadeScalarMultiply(const Element &x, const Integer &e1, const Element &y, const Integer &e2) const
|
||||
{return GetRing().CascadeExponentiate(x, e1, y, e2);}
|
||||
|
||||
void SimultaneousMultiply(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const
|
||||
{GetRing().SimultaneousExponentiate(results, base, exponents, exponentsCount);}
|
||||
|
||||
const AbstractRing<T> *m_pRing;
|
||||
};
|
||||
|
||||
MultiplicativeGroupT m_mg;
|
||||
};
|
||||
|
||||
// ********************************************************
|
||||
|
||||
/// \brief Base and exponent
|
||||
/// \tparam T base class or type
|
||||
/// \tparam E exponent class or type
|
||||
template <class T, class E = Integer>
|
||||
struct BaseAndExponent
|
||||
{
|
||||
public:
|
||||
BaseAndExponent() {}
|
||||
BaseAndExponent(const T &base, const E &exponent) : base(base), exponent(exponent) {}
|
||||
bool operator<(const BaseAndExponent<T, E> &rhs) const {return exponent < rhs.exponent;}
|
||||
T base;
|
||||
E exponent;
|
||||
};
|
||||
|
||||
// VC60 workaround: incomplete member template support
|
||||
template <class Element, class Iterator>
|
||||
Element GeneralCascadeMultiplication(const AbstractGroup<Element> &group, Iterator begin, Iterator end);
|
||||
template <class Element, class Iterator>
|
||||
Element GeneralCascadeExponentiation(const AbstractRing<Element> &ring, Iterator begin, Iterator end);
|
||||
|
||||
// ********************************************************
|
||||
|
||||
/// \brief Abstract Euclidean domain
|
||||
/// \tparam T element class or type
|
||||
/// \details <tt>const Element&</tt> returned by member functions are references
|
||||
/// to internal data members. Since each object may have only
|
||||
/// one such data member for holding results, the following code
|
||||
/// will produce incorrect results:
|
||||
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
|
||||
/// But this should be fine:
|
||||
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
|
||||
template <class T> class CRYPTOPP_NO_VTABLE AbstractEuclideanDomain : public AbstractRing<T>
|
||||
{
|
||||
public:
|
||||
typedef T Element;
|
||||
|
||||
/// \brief Performs the division algorithm on two elements in the ring
|
||||
/// \param r the remainder
|
||||
/// \param q the quotient
|
||||
/// \param a the dividend
|
||||
/// \param d the divisor
|
||||
virtual void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const =0;
|
||||
|
||||
/// \brief Performs a modular reduction in the ring
|
||||
/// \param a the element
|
||||
/// \param b the modulus
|
||||
/// \return the result of <tt>a%b</tt>.
|
||||
virtual const Element& Mod(const Element &a, const Element &b) const =0;
|
||||
|
||||
/// \brief Calculates the greatest common denominator in the ring
|
||||
/// \param a the first element
|
||||
/// \param b the second element
|
||||
/// \return the greatest common denominator of a and b.
|
||||
virtual const Element& Gcd(const Element &a, const Element &b) const;
|
||||
|
||||
protected:
|
||||
mutable Element result;
|
||||
};
|
||||
|
||||
// ********************************************************
|
||||
|
||||
/// \brief Euclidean domain
|
||||
/// \tparam T element class or type
|
||||
/// \details <tt>const Element&</tt> returned by member functions are references
|
||||
/// to internal data members. Since each object may have only
|
||||
/// one such data member for holding results, the following code
|
||||
/// will produce incorrect results:
|
||||
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
|
||||
/// But this should be fine:
|
||||
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
|
||||
template <class T> class EuclideanDomainOf : public AbstractEuclideanDomain<T>
|
||||
{
|
||||
public:
|
||||
typedef T Element;
|
||||
|
||||
EuclideanDomainOf() {}
|
||||
|
||||
bool Equal(const Element &a, const Element &b) const
|
||||
{return a==b;}
|
||||
|
||||
const Element& Identity() const
|
||||
{return Element::Zero();}
|
||||
|
||||
const Element& Add(const Element &a, const Element &b) const
|
||||
{return result = a+b;}
|
||||
|
||||
Element& Accumulate(Element &a, const Element &b) const
|
||||
{return a+=b;}
|
||||
|
||||
const Element& Inverse(const Element &a) const
|
||||
{return result = -a;}
|
||||
|
||||
const Element& Subtract(const Element &a, const Element &b) const
|
||||
{return result = a-b;}
|
||||
|
||||
Element& Reduce(Element &a, const Element &b) const
|
||||
{return a-=b;}
|
||||
|
||||
const Element& Double(const Element &a) const
|
||||
{return result = a.Doubled();}
|
||||
|
||||
const Element& MultiplicativeIdentity() const
|
||||
{return Element::One();}
|
||||
|
||||
const Element& Multiply(const Element &a, const Element &b) const
|
||||
{return result = a*b;}
|
||||
|
||||
const Element& Square(const Element &a) const
|
||||
{return result = a.Squared();}
|
||||
|
||||
bool IsUnit(const Element &a) const
|
||||
{return a.IsUnit();}
|
||||
|
||||
const Element& MultiplicativeInverse(const Element &a) const
|
||||
{return result = a.MultiplicativeInverse();}
|
||||
|
||||
const Element& Divide(const Element &a, const Element &b) const
|
||||
{return result = a/b;}
|
||||
|
||||
const Element& Mod(const Element &a, const Element &b) const
|
||||
{return result = a%b;}
|
||||
|
||||
void DivisionAlgorithm(Element &r, Element &q, const Element &a, const Element &d) const
|
||||
{Element::Divide(r, q, a, d);}
|
||||
|
||||
bool operator==(const EuclideanDomainOf<T> &rhs) const
|
||||
{CRYPTOPP_UNUSED(rhs); return true;}
|
||||
|
||||
private:
|
||||
mutable Element result;
|
||||
};
|
||||
|
||||
/// \brief Quotient ring
|
||||
/// \tparam T element class or type
|
||||
/// \details <tt>const Element&</tt> returned by member functions are references
|
||||
/// to internal data members. Since each object may have only
|
||||
/// one such data member for holding results, the following code
|
||||
/// will produce incorrect results:
|
||||
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
|
||||
/// But this should be fine:
|
||||
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
|
||||
template <class T> class QuotientRing : public AbstractRing<typename T::Element>
|
||||
{
|
||||
public:
|
||||
typedef T EuclideanDomain;
|
||||
typedef typename T::Element Element;
|
||||
|
||||
QuotientRing(const EuclideanDomain &domain, const Element &modulus)
|
||||
: m_domain(domain), m_modulus(modulus) {}
|
||||
|
||||
const EuclideanDomain & GetDomain() const
|
||||
{return m_domain;}
|
||||
|
||||
const Element& GetModulus() const
|
||||
{return m_modulus;}
|
||||
|
||||
bool Equal(const Element &a, const Element &b) const
|
||||
{return m_domain.Equal(m_domain.Mod(m_domain.Subtract(a, b), m_modulus), m_domain.Identity());}
|
||||
|
||||
const Element& Identity() const
|
||||
{return m_domain.Identity();}
|
||||
|
||||
const Element& Add(const Element &a, const Element &b) const
|
||||
{return m_domain.Add(a, b);}
|
||||
|
||||
Element& Accumulate(Element &a, const Element &b) const
|
||||
{return m_domain.Accumulate(a, b);}
|
||||
|
||||
const Element& Inverse(const Element &a) const
|
||||
{return m_domain.Inverse(a);}
|
||||
|
||||
const Element& Subtract(const Element &a, const Element &b) const
|
||||
{return m_domain.Subtract(a, b);}
|
||||
|
||||
Element& Reduce(Element &a, const Element &b) const
|
||||
{return m_domain.Reduce(a, b);}
|
||||
|
||||
const Element& Double(const Element &a) const
|
||||
{return m_domain.Double(a);}
|
||||
|
||||
bool IsUnit(const Element &a) const
|
||||
{return m_domain.IsUnit(m_domain.Gcd(a, m_modulus));}
|
||||
|
||||
const Element& MultiplicativeIdentity() const
|
||||
{return m_domain.MultiplicativeIdentity();}
|
||||
|
||||
const Element& Multiply(const Element &a, const Element &b) const
|
||||
{return m_domain.Mod(m_domain.Multiply(a, b), m_modulus);}
|
||||
|
||||
const Element& Square(const Element &a) const
|
||||
{return m_domain.Mod(m_domain.Square(a), m_modulus);}
|
||||
|
||||
const Element& MultiplicativeInverse(const Element &a) const;
|
||||
|
||||
bool operator==(const QuotientRing<T> &rhs) const
|
||||
{return m_domain == rhs.m_domain && m_modulus == rhs.m_modulus;}
|
||||
|
||||
protected:
|
||||
EuclideanDomain m_domain;
|
||||
Element m_modulus;
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#ifdef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
|
||||
#include "algebra.cpp"
|
||||
#endif
|
||||
|
||||
#endif
|
520
wasm_src/algparam.h
Normal file
520
wasm_src/algparam.h
Normal file
@ -0,0 +1,520 @@
|
||||
// algparam.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file algparam.h
|
||||
/// \brief Classes for working with NameValuePairs
|
||||
|
||||
#ifndef CRYPTOPP_ALGPARAM_H
|
||||
#define CRYPTOPP_ALGPARAM_H
|
||||
|
||||
#include "config.h"
|
||||
#include "cryptlib.h"
|
||||
|
||||
#include "smartptr.h"
|
||||
#include "secblock.h"
|
||||
#include "integer.h"
|
||||
#include "misc.h"
|
||||
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <exception>
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
/// \brief Used to pass byte array input as part of a NameValuePairs object
|
||||
class ConstByteArrayParameter
|
||||
{
|
||||
public:
|
||||
/// \brief Construct a ConstByteArrayParameter
|
||||
/// \param data a C-String
|
||||
/// \param deepCopy flag indicating whether the data should be copied
|
||||
/// \details The deepCopy option is used when the NameValuePairs object can't
|
||||
/// keep a copy of the data available
|
||||
ConstByteArrayParameter(const char *data = NULLPTR, bool deepCopy = false)
|
||||
: m_deepCopy(false), m_data(NULLPTR), m_size(0)
|
||||
{
|
||||
Assign(reinterpret_cast<const byte *>(data), data ? strlen(data) : 0, deepCopy);
|
||||
}
|
||||
|
||||
/// \brief Construct a ConstByteArrayParameter
|
||||
/// \param data a memory buffer
|
||||
/// \param size the length of the memory buffer
|
||||
/// \param deepCopy flag indicating whether the data should be copied
|
||||
/// \details The deepCopy option is used when the NameValuePairs object can't
|
||||
/// keep a copy of the data available
|
||||
ConstByteArrayParameter(const byte *data, size_t size, bool deepCopy = false)
|
||||
: m_deepCopy(false), m_data(NULLPTR), m_size(0)
|
||||
{
|
||||
Assign(data, size, deepCopy);
|
||||
}
|
||||
|
||||
/// \brief Construct a ConstByteArrayParameter
|
||||
/// \tparam T a std::basic_string<char> or std::vector<byte> class
|
||||
/// \param string a std::basic_string<char> or std::vector<byte> object
|
||||
/// \param deepCopy flag indicating whether the data should be copied
|
||||
/// \details The deepCopy option is used when the NameValuePairs object can't
|
||||
/// keep a copy of the data available
|
||||
template <class T> ConstByteArrayParameter(const T &string, bool deepCopy = false)
|
||||
: m_deepCopy(false), m_data(NULLPTR), m_size(0)
|
||||
{
|
||||
CRYPTOPP_COMPILE_ASSERT(sizeof(typename T::value_type) == 1);
|
||||
Assign(reinterpret_cast<const byte *>(&string[0]), string.size(), deepCopy);
|
||||
}
|
||||
|
||||
/// \brief Assign contents from a memory buffer
|
||||
/// \param data a memory buffer
|
||||
/// \param size the length of the memory buffer
|
||||
/// \param deepCopy flag indicating whether the data should be copied
|
||||
/// \details The deepCopy option is used when the NameValuePairs object can't
|
||||
/// keep a copy of the data available
|
||||
void Assign(const byte *data, size_t size, bool deepCopy)
|
||||
{
|
||||
// This fires, which means: no data with a size, or data with no size.
|
||||
// CRYPTOPP_ASSERT((data && size) || !(data || size));
|
||||
if (deepCopy)
|
||||
m_block.Assign(data, size);
|
||||
else
|
||||
{
|
||||
m_data = data;
|
||||
m_size = size;
|
||||
}
|
||||
m_deepCopy = deepCopy;
|
||||
}
|
||||
|
||||
/// \brief Pointer to the first byte in the memory block
|
||||
const byte *begin() const {return m_deepCopy ? m_block.begin() : m_data;}
|
||||
/// \brief Pointer beyond the last byte in the memory block
|
||||
const byte *end() const {return m_deepCopy ? m_block.end() : m_data + m_size;}
|
||||
/// \brief Length of the memory block
|
||||
size_t size() const {return m_deepCopy ? m_block.size() : m_size;}
|
||||
|
||||
private:
|
||||
bool m_deepCopy;
|
||||
const byte *m_data;
|
||||
size_t m_size;
|
||||
SecByteBlock m_block;
|
||||
};
|
||||
|
||||
/// \brief Used to pass byte array input as part of a NameValuePairs object
|
||||
class ByteArrayParameter
|
||||
{
|
||||
public:
|
||||
/// \brief Construct a ByteArrayParameter
|
||||
/// \param data a memory buffer
|
||||
/// \param size the length of the memory buffer
|
||||
ByteArrayParameter(byte *data = NULLPTR, unsigned int size = 0)
|
||||
: m_data(data), m_size(size) {}
|
||||
|
||||
/// \brief Construct a ByteArrayParameter
|
||||
/// \param block a SecByteBlock
|
||||
ByteArrayParameter(SecByteBlock &block)
|
||||
: m_data(block.begin()), m_size(block.size()) {}
|
||||
|
||||
/// \brief Pointer to the first byte in the memory block
|
||||
byte *begin() const {return m_data;}
|
||||
/// \brief Pointer beyond the last byte in the memory block
|
||||
byte *end() const {return m_data + m_size;}
|
||||
/// \brief Length of the memory block
|
||||
size_t size() const {return m_size;}
|
||||
|
||||
private:
|
||||
byte *m_data;
|
||||
size_t m_size;
|
||||
};
|
||||
|
||||
/// \brief Combines two sets of NameValuePairs
|
||||
/// \details CombinedNameValuePairs allows you to provide two sets of of NameValuePairs.
|
||||
/// If a name is not found in the first set, then the second set is searched for the
|
||||
/// name and value pair. The second set of NameValuePairs often provides default values.
|
||||
class CRYPTOPP_DLL CombinedNameValuePairs : public NameValuePairs
|
||||
{
|
||||
public:
|
||||
/// \brief Construct a CombinedNameValuePairs
|
||||
/// \param pairs1 reference to the first set of NameValuePairs
|
||||
/// \param pairs2 reference to the second set of NameValuePairs
|
||||
CombinedNameValuePairs(const NameValuePairs &pairs1, const NameValuePairs &pairs2)
|
||||
: m_pairs1(pairs1), m_pairs2(pairs2) {}
|
||||
|
||||
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
|
||||
|
||||
private:
|
||||
const NameValuePairs &m_pairs1, &m_pairs2;
|
||||
};
|
||||
|
||||
#ifndef CRYPTOPP_DOXYGEN_PROCESSING
|
||||
template <class T, class BASE>
|
||||
class GetValueHelperClass
|
||||
{
|
||||
public:
|
||||
GetValueHelperClass(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst)
|
||||
: m_pObject(pObject), m_name(name), m_valueType(&valueType), m_pValue(pValue), m_found(false), m_getValueNames(false)
|
||||
{
|
||||
if (strcmp(m_name, "ValueNames") == 0)
|
||||
{
|
||||
m_found = m_getValueNames = true;
|
||||
NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(std::string), *m_valueType);
|
||||
if (searchFirst)
|
||||
searchFirst->GetVoidValue(m_name, valueType, pValue);
|
||||
if (typeid(T) != typeid(BASE))
|
||||
pObject->BASE::GetVoidValue(m_name, valueType, pValue);
|
||||
((*reinterpret_cast<std::string *>(m_pValue) += "ThisPointer:") += typeid(T).name()) += ';';
|
||||
}
|
||||
|
||||
if (!m_found && strncmp(m_name, "ThisPointer:", 12) == 0 && strcmp(m_name+12, typeid(T).name()) == 0)
|
||||
{
|
||||
NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T *), *m_valueType);
|
||||
*reinterpret_cast<const T **>(pValue) = pObject;
|
||||
m_found = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_found && searchFirst)
|
||||
m_found = searchFirst->GetVoidValue(m_name, valueType, pValue);
|
||||
|
||||
if (!m_found && typeid(T) != typeid(BASE))
|
||||
m_found = pObject->BASE::GetVoidValue(m_name, valueType, pValue);
|
||||
}
|
||||
|
||||
operator bool() const {return m_found;}
|
||||
|
||||
template <class R>
|
||||
GetValueHelperClass<T,BASE> & operator()(const char *name, const R & (T::*pm)() const)
|
||||
{
|
||||
if (m_getValueNames)
|
||||
(*reinterpret_cast<std::string *>(m_pValue) += name) += ";";
|
||||
if (!m_found && strcmp(name, m_name) == 0)
|
||||
{
|
||||
NameValuePairs::ThrowIfTypeMismatch(name, typeid(R), *m_valueType);
|
||||
*reinterpret_cast<R *>(m_pValue) = (m_pObject->*pm)();
|
||||
m_found = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
GetValueHelperClass<T,BASE> &Assignable()
|
||||
{
|
||||
#ifndef __INTEL_COMPILER // ICL 9.1 workaround: Intel compiler copies the vTable pointer for some reason
|
||||
if (m_getValueNames)
|
||||
((*reinterpret_cast<std::string *>(m_pValue) += "ThisObject:") += typeid(T).name()) += ';';
|
||||
if (!m_found && strncmp(m_name, "ThisObject:", 11) == 0 && strcmp(m_name+11, typeid(T).name()) == 0)
|
||||
{
|
||||
NameValuePairs::ThrowIfTypeMismatch(m_name, typeid(T), *m_valueType);
|
||||
*reinterpret_cast<T *>(m_pValue) = *m_pObject;
|
||||
m_found = true;
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const T *m_pObject;
|
||||
const char *m_name;
|
||||
const std::type_info *m_valueType;
|
||||
void *m_pValue;
|
||||
bool m_found, m_getValueNames;
|
||||
};
|
||||
|
||||
template <class BASE, class T>
|
||||
GetValueHelperClass<T, BASE> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR)
|
||||
{
|
||||
return GetValueHelperClass<T, BASE>(pObject, name, valueType, pValue, searchFirst);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
GetValueHelperClass<T, T> GetValueHelper(const T *pObject, const char *name, const std::type_info &valueType, void *pValue, const NameValuePairs *searchFirst=NULLPTR)
|
||||
{
|
||||
return GetValueHelperClass<T, T>(pObject, name, valueType, pValue, searchFirst);
|
||||
}
|
||||
|
||||
// ********************************************************
|
||||
|
||||
template <class T, class BASE>
|
||||
class AssignFromHelperClass
|
||||
{
|
||||
public:
|
||||
AssignFromHelperClass(T *pObject, const NameValuePairs &source)
|
||||
: m_pObject(pObject), m_source(source), m_done(false)
|
||||
{
|
||||
if (source.GetThisObject(*pObject))
|
||||
m_done = true;
|
||||
else if (typeid(BASE) != typeid(T))
|
||||
pObject->BASE::AssignFrom(source);
|
||||
}
|
||||
|
||||
template <class R>
|
||||
AssignFromHelperClass & operator()(const char *name, void (T::*pm)(const R&))
|
||||
{
|
||||
if (!m_done)
|
||||
{
|
||||
R value;
|
||||
if (!m_source.GetValue(name, value))
|
||||
throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name + "'");
|
||||
(m_pObject->*pm)(value);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class R, class S>
|
||||
AssignFromHelperClass & operator()(const char *name1, const char *name2, void (T::*pm)(const R&, const S&))
|
||||
{
|
||||
if (!m_done)
|
||||
{
|
||||
R value1;
|
||||
if (!m_source.GetValue(name1, value1))
|
||||
throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name1 + "'");
|
||||
S value2;
|
||||
if (!m_source.GetValue(name2, value2))
|
||||
throw InvalidArgument(std::string(typeid(T).name()) + ": Missing required parameter '" + name2 + "'");
|
||||
(m_pObject->*pm)(value1, value2);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
T *m_pObject;
|
||||
const NameValuePairs &m_source;
|
||||
bool m_done;
|
||||
};
|
||||
|
||||
template <class BASE, class T>
|
||||
AssignFromHelperClass<T, BASE> AssignFromHelper(T *pObject, const NameValuePairs &source)
|
||||
{
|
||||
return AssignFromHelperClass<T, BASE>(pObject, source);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
AssignFromHelperClass<T, T> AssignFromHelper(T *pObject, const NameValuePairs &source)
|
||||
{
|
||||
return AssignFromHelperClass<T, T>(pObject, source);
|
||||
}
|
||||
|
||||
#endif // CRYPTOPP_DOXYGEN_PROCESSING
|
||||
|
||||
// ********************************************************
|
||||
|
||||
#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER
|
||||
// Allow the linker to discard Integer code if not needed.
|
||||
// Also see http://github.com/weidai11/cryptopp/issues/389.
|
||||
CRYPTOPP_DLL bool AssignIntToInteger(const std::type_info &valueType, void *pInteger, const void *pInt);
|
||||
#endif
|
||||
|
||||
CRYPTOPP_DLL const std::type_info & CRYPTOPP_API IntegerTypeId();
|
||||
|
||||
/// \brief Base class for AlgorithmParameters
|
||||
class CRYPTOPP_DLL AlgorithmParametersBase
|
||||
{
|
||||
public:
|
||||
/// \brief Exception thrown when an AlgorithmParameter is unused
|
||||
class ParameterNotUsed : public Exception
|
||||
{
|
||||
public:
|
||||
ParameterNotUsed(const char *name) : Exception(OTHER_ERROR, std::string("AlgorithmParametersBase: parameter \"") + name + "\" not used") {}
|
||||
};
|
||||
|
||||
virtual ~AlgorithmParametersBase() CRYPTOPP_THROW
|
||||
{
|
||||
|
||||
#if defined(CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS)
|
||||
if (std::uncaught_exceptions() == 0)
|
||||
#elif defined(CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION)
|
||||
if (std::uncaught_exception() == false)
|
||||
#else
|
||||
try
|
||||
#endif
|
||||
{
|
||||
if (m_throwIfNotUsed && !m_used)
|
||||
throw ParameterNotUsed(m_name);
|
||||
}
|
||||
#if !defined(CRYPTOPP_CXX98_UNCAUGHT_EXCEPTION)
|
||||
# if !defined(CRYPTOPP_CXX17_UNCAUGHT_EXCEPTIONS)
|
||||
catch(const Exception&)
|
||||
{
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// this is actually a move, not a copy
|
||||
AlgorithmParametersBase(const AlgorithmParametersBase &x)
|
||||
: m_name(x.m_name), m_throwIfNotUsed(x.m_throwIfNotUsed), m_used(x.m_used)
|
||||
{
|
||||
m_next.reset(const_cast<AlgorithmParametersBase &>(x).m_next.release());
|
||||
x.m_used = true;
|
||||
}
|
||||
|
||||
/// \brief Construct a AlgorithmParametersBase
|
||||
/// \param name the parameter name
|
||||
/// \param throwIfNotUsed flags indicating whether an exception should be thrown
|
||||
/// \details If throwIfNotUsed is true, then a ParameterNotUsed exception
|
||||
/// will be thrown in the destructor if the parameter is not not retrieved.
|
||||
AlgorithmParametersBase(const char *name, bool throwIfNotUsed)
|
||||
: m_name(name), m_throwIfNotUsed(throwIfNotUsed), m_used(false) {}
|
||||
|
||||
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
|
||||
|
||||
protected:
|
||||
friend class AlgorithmParameters;
|
||||
void operator=(const AlgorithmParametersBase& rhs); // assignment not allowed, declare this for VC60
|
||||
|
||||
virtual void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const =0;
|
||||
virtual void MoveInto(void *p) const =0; // not really const
|
||||
|
||||
const char *m_name;
|
||||
bool m_throwIfNotUsed;
|
||||
mutable bool m_used;
|
||||
member_ptr<AlgorithmParametersBase> m_next;
|
||||
};
|
||||
|
||||
/// \brief Template base class for AlgorithmParameters
|
||||
/// \tparam T the class or type
|
||||
template <class T>
|
||||
class AlgorithmParametersTemplate : public AlgorithmParametersBase
|
||||
{
|
||||
public:
|
||||
/// \brief Construct an AlgorithmParametersTemplate
|
||||
/// \param name the name of the value
|
||||
/// \param value a reference to the value
|
||||
/// \param throwIfNotUsed flags indicating whether an exception should be thrown
|
||||
/// \details If throwIfNotUsed is true, then a ParameterNotUsed exception
|
||||
/// will be thrown in the destructor if the parameter is not not retrieved.
|
||||
AlgorithmParametersTemplate(const char *name, const T &value, bool throwIfNotUsed)
|
||||
: AlgorithmParametersBase(name, throwIfNotUsed), m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
void AssignValue(const char *name, const std::type_info &valueType, void *pValue) const
|
||||
{
|
||||
#ifndef CRYPTOPP_NO_ASSIGN_TO_INTEGER
|
||||
// Special case for retrieving an Integer parameter when an int was passed in
|
||||
if (!(typeid(T) == typeid(int) && AssignIntToInteger(valueType, pValue, &m_value)))
|
||||
#endif
|
||||
{
|
||||
NameValuePairs::ThrowIfTypeMismatch(name, typeid(T), valueType);
|
||||
*reinterpret_cast<T *>(pValue) = m_value;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG_NEW) && (_MSC_VER >= 1300)
|
||||
# pragma push_macro("new")
|
||||
# undef new
|
||||
#endif
|
||||
|
||||
void MoveInto(void *buffer) const
|
||||
{
|
||||
AlgorithmParametersTemplate<T>* p = new(buffer) AlgorithmParametersTemplate<T>(*this);
|
||||
CRYPTOPP_UNUSED(p); // silence warning
|
||||
}
|
||||
|
||||
#if defined(DEBUG_NEW) && (_MSC_VER >= 1300)
|
||||
# pragma pop_macro("new")
|
||||
#endif
|
||||
|
||||
protected:
|
||||
T m_value;
|
||||
};
|
||||
|
||||
CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<bool>;
|
||||
CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<int>;
|
||||
CRYPTOPP_DLL_TEMPLATE_CLASS AlgorithmParametersTemplate<ConstByteArrayParameter>;
|
||||
|
||||
/// \brief An object that implements NameValuePairs
|
||||
/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
|
||||
/// repeatedly using operator() on the object returned by MakeParameters, for example:
|
||||
/// <pre>
|
||||
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
|
||||
/// </pre>
|
||||
class CRYPTOPP_DLL AlgorithmParameters : public NameValuePairs
|
||||
{
|
||||
public:
|
||||
/// \brief Construct a AlgorithmParameters
|
||||
/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
|
||||
/// repeatedly using operator() on the object returned by MakeParameters, for example:
|
||||
/// <pre>
|
||||
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
|
||||
/// </pre>
|
||||
AlgorithmParameters();
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
/// \brief Construct a AlgorithmParameters
|
||||
/// \tparam T the class or type
|
||||
/// \param name the name of the object or value to retrieve
|
||||
/// \param value reference to a variable that receives the value
|
||||
/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
|
||||
/// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(),
|
||||
/// such as MSVC 7.0 and earlier.
|
||||
/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
|
||||
/// repeatedly using operator() on the object returned by MakeParameters, for example:
|
||||
/// <pre>
|
||||
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
|
||||
/// </pre>
|
||||
template <class T>
|
||||
AlgorithmParameters(const char *name, const T &value, bool throwIfNotUsed=true)
|
||||
: m_next(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed))
|
||||
, m_defaultThrowIfNotUsed(throwIfNotUsed)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
AlgorithmParameters(const AlgorithmParameters &x);
|
||||
|
||||
AlgorithmParameters & operator=(const AlgorithmParameters &x);
|
||||
|
||||
/// \tparam T the class or type
|
||||
/// \param name the name of the object or value to retrieve
|
||||
/// \param value reference to a variable that receives the value
|
||||
/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
|
||||
template <class T>
|
||||
AlgorithmParameters & operator()(const char *name, const T &value, bool throwIfNotUsed)
|
||||
{
|
||||
member_ptr<AlgorithmParametersBase> p(new AlgorithmParametersTemplate<T>(name, value, throwIfNotUsed));
|
||||
p->m_next.reset(m_next.release());
|
||||
m_next.reset(p.release());
|
||||
m_defaultThrowIfNotUsed = throwIfNotUsed;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Appends a NameValuePair to a collection of NameValuePairs
|
||||
/// \tparam T the class or type
|
||||
/// \param name the name of the object or value to retrieve
|
||||
/// \param value reference to a variable that receives the value
|
||||
template <class T>
|
||||
AlgorithmParameters & operator()(const char *name, const T &value)
|
||||
{
|
||||
return operator()(name, value, m_defaultThrowIfNotUsed);
|
||||
}
|
||||
|
||||
bool GetVoidValue(const char *name, const std::type_info &valueType, void *pValue) const;
|
||||
|
||||
protected:
|
||||
member_ptr<AlgorithmParametersBase> m_next;
|
||||
bool m_defaultThrowIfNotUsed;
|
||||
};
|
||||
|
||||
/// \brief Create an object that implements NameValuePairs
|
||||
/// \tparam T the class or type
|
||||
/// \param name the name of the object or value to retrieve
|
||||
/// \param value reference to a variable that receives the value
|
||||
/// \param throwIfNotUsed if true, the object will throw an exception if the value is not accessed
|
||||
/// \note throwIfNotUsed is ignored if using a compiler that does not support std::uncaught_exception(),
|
||||
/// such as MSVC 7.0 and earlier.
|
||||
/// \note A NameValuePairs object containing an arbitrary number of name value pairs may be constructed by
|
||||
/// repeatedly using \p operator() on the object returned by \p MakeParameters, for example:
|
||||
/// <pre>
|
||||
/// AlgorithmParameters parameters = MakeParameters(name1, value1)(name2, value2)(name3, value3);
|
||||
/// </pre>
|
||||
#ifdef __BORLANDC__
|
||||
typedef AlgorithmParameters MakeParameters;
|
||||
#else
|
||||
template <class T>
|
||||
AlgorithmParameters MakeParameters(const char *name, const T &value, bool throwIfNotUsed = true)
|
||||
{
|
||||
return AlgorithmParameters()(name, value, throwIfNotUsed);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define CRYPTOPP_GET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Get##name)
|
||||
#define CRYPTOPP_SET_FUNCTION_ENTRY(name) (Name::name(), &ThisClass::Set##name)
|
||||
#define CRYPTOPP_SET_FUNCTION_ENTRY2(name1, name2) (Name::name1(), Name::name2(), &ThisClass::Set##name1##And##name2)
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
107
wasm_src/allocate.cpp
Normal file
107
wasm_src/allocate.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
// allocate.cpp - written and placed in the public domain by Jeffrey Walton
|
||||
|
||||
// The functions in allocate.h and allocate.cpp were originally in misc.h
|
||||
// and misc.cpp. They were extracted in September 2019 to sidestep a circular
|
||||
// dependency with misc.h and secblock.h.
|
||||
|
||||
#include "pch.h"
|
||||
#include "config.h"
|
||||
|
||||
#ifndef CRYPTOPP_IMPORTS
|
||||
|
||||
#include "allocate.h"
|
||||
#include "stdcpp.h"
|
||||
#include "misc.h"
|
||||
|
||||
|
||||
// for memalign
|
||||
#if defined(CRYPTOPP_MEMALIGN_AVAILABLE) || defined(CRYPTOPP_MM_MALLOC_AVAILABLE) || defined(QNX)
|
||||
# include <malloc.h>
|
||||
#endif
|
||||
// for posix_memalign
|
||||
#if defined(CRYPTOPP_POSIX_MEMALIGN_AVAILABLE)
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
void CallNewHandler()
|
||||
{
|
||||
using std::new_handler;
|
||||
using std::set_new_handler;
|
||||
|
||||
new_handler newHandler = set_new_handler(NULLPTR);
|
||||
if (newHandler)
|
||||
set_new_handler(newHandler);
|
||||
|
||||
if (newHandler)
|
||||
newHandler();
|
||||
else
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
void * AlignedAllocate(size_t size)
|
||||
{
|
||||
byte *p;
|
||||
#if defined(CRYPTOPP_MM_MALLOC_AVAILABLE)
|
||||
while ((p = (byte *)_mm_malloc(size, 16)) == NULLPTR)
|
||||
#elif defined(CRYPTOPP_MEMALIGN_AVAILABLE)
|
||||
while ((p = (byte *)memalign(16, size)) == NULLPTR)
|
||||
#elif defined(CRYPTOPP_MALLOC_ALIGNMENT_IS_16)
|
||||
while ((p = (byte *)malloc(size)) == NULLPTR)
|
||||
#elif defined(CRYPTOPP_POSIX_MEMALIGN_AVAILABLE)
|
||||
while (posix_memalign(reinterpret_cast<void**>(&p), 16, size) != 0)
|
||||
#else
|
||||
while ((p = (byte *)malloc(size + 16)) == NULLPTR)
|
||||
#endif
|
||||
CallNewHandler();
|
||||
|
||||
#ifdef CRYPTOPP_NO_ALIGNED_ALLOC
|
||||
size_t adjustment = 16-((size_t)p%16);
|
||||
CRYPTOPP_ASSERT(adjustment > 0);
|
||||
p += adjustment;
|
||||
p[-1] = (byte)adjustment;
|
||||
#endif
|
||||
|
||||
// If this assert fires then there are problems that need
|
||||
// to be fixed. Please open a bug report.
|
||||
CRYPTOPP_ASSERT(IsAlignedOn(p, 16));
|
||||
return p;
|
||||
}
|
||||
|
||||
void AlignedDeallocate(void *p)
|
||||
{
|
||||
// Guard pointer due to crash on AIX when CRYPTOPP_NO_ALIGNED_ALLOC
|
||||
// is in effect. The guard was previously in place in SecBlock,
|
||||
// but it was removed at f4d68353ca7c as part of GH #875.
|
||||
CRYPTOPP_ASSERT(p);
|
||||
|
||||
if (p != NULLPTR)
|
||||
{
|
||||
#ifdef CRYPTOPP_MM_MALLOC_AVAILABLE
|
||||
_mm_free(p);
|
||||
#elif defined(CRYPTOPP_NO_ALIGNED_ALLOC)
|
||||
p = (byte *)p - ((byte *)p)[-1];
|
||||
free(p);
|
||||
#else
|
||||
free(p);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void * UnalignedAllocate(size_t size)
|
||||
{
|
||||
void *p;
|
||||
while ((p = malloc(size)) == NULLPTR)
|
||||
CallNewHandler();
|
||||
return p;
|
||||
}
|
||||
|
||||
void UnalignedDeallocate(void *p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif // CRYPTOPP_IMPORTS
|
74
wasm_src/allocate.h
Normal file
74
wasm_src/allocate.h
Normal file
@ -0,0 +1,74 @@
|
||||
// allocate.h - written and placed in the public domain by Jeffrey Walton
|
||||
|
||||
// The functions in allocate.h and allocate.cpp were originally in misc.h
|
||||
// and misc.cpp. They were extracted in September 2019 to sidestep a circular
|
||||
// dependency with misc.h and secblock.h.
|
||||
|
||||
/// \file allocate.h
|
||||
/// \brief Functions for allocating aligned buffers
|
||||
|
||||
#ifndef CRYPTOPP_ALLOCATE_H
|
||||
#define CRYPTOPP_ALLOCATE_H
|
||||
|
||||
#include "config.h"
|
||||
#include "cryptlib.h"
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
/// \brief Attempts to reclaim unused memory
|
||||
/// \throw bad_alloc
|
||||
/// \details In the normal course of running a program, a request for memory
|
||||
/// normally succeeds. If a call to AlignedAllocate or UnalignedAllocate fails,
|
||||
/// then CallNewHandler is called in n effort to recover. Internally,
|
||||
/// CallNewHandler calls set_new_handler(nullptr) in an effort to free memory.
|
||||
/// There is no guarantee CallNewHandler will be able to obtain more memory so
|
||||
/// an allocation succeeds. If the call to set_new_handler fails, then CallNewHandler
|
||||
/// throws a bad_alloc exception.
|
||||
/// \throw bad_alloc on failure
|
||||
/// \since Crypto++ 5.0
|
||||
/// \sa AlignedAllocate, AlignedDeallocate, UnalignedAllocate, UnalignedDeallocate
|
||||
CRYPTOPP_DLL void CRYPTOPP_API CallNewHandler();
|
||||
|
||||
/// \brief Allocates a buffer on 16-byte boundary
|
||||
/// \param size the size of the buffer
|
||||
/// \details AlignedAllocate is primarily used when the data will be
|
||||
/// processed by SSE, NEON, ARMv8 or PowerPC instructions. The assembly
|
||||
/// language routines rely on the alignment. If the alignment is not
|
||||
/// respected, then a SIGBUS could be generated on Unix and Linux, and an
|
||||
/// EXCEPTION_DATATYPE_MISALIGNMENT could be generated on Windows.
|
||||
/// \details Formerly, AlignedAllocate and AlignedDeallocate were only
|
||||
/// available on certain platforms when CRYTPOPP_DISABLE_ASM was not in
|
||||
/// effect. However, Android and iOS debug simulator builds got into a
|
||||
/// state where the aligned allocator was not available and caused link
|
||||
/// failures.
|
||||
/// \since AlignedAllocate for SIMD since Crypto++ 1.0, AlignedAllocate
|
||||
/// for all builds since Crypto++ 8.1
|
||||
/// \sa AlignedDeallocate, UnalignedAllocate, UnalignedDeallocate, CallNewHandler,
|
||||
/// <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
|
||||
CRYPTOPP_DLL void* CRYPTOPP_API AlignedAllocate(size_t size);
|
||||
|
||||
/// \brief Frees a buffer allocated with AlignedAllocate
|
||||
/// \param ptr the buffer to free
|
||||
/// \since AlignedDeallocate for SIMD since Crypto++ 1.0, AlignedAllocate
|
||||
/// for all builds since Crypto++ 8.1
|
||||
/// \sa AlignedAllocate, UnalignedAllocate, UnalignedDeallocate, CallNewHandler,
|
||||
/// <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
|
||||
CRYPTOPP_DLL void CRYPTOPP_API AlignedDeallocate(void *ptr);
|
||||
|
||||
/// \brief Allocates a buffer
|
||||
/// \param size the size of the buffer
|
||||
/// \since Crypto++ 1.0
|
||||
/// \sa AlignedAllocate, AlignedDeallocate, UnalignedDeallocate, CallNewHandler,
|
||||
/// <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
|
||||
CRYPTOPP_DLL void * CRYPTOPP_API UnalignedAllocate(size_t size);
|
||||
|
||||
/// \brief Frees a buffer allocated with UnalignedAllocate
|
||||
/// \param ptr the buffer to free
|
||||
/// \since Crypto++ 1.0
|
||||
/// \sa AlignedAllocate, AlignedDeallocate, UnalignedAllocate, CallNewHandler,
|
||||
/// <A HREF="http://github.com/weidai11/cryptopp/issues/779">Issue 779</A>
|
||||
CRYPTOPP_DLL void CRYPTOPP_API UnalignedDeallocate(void *ptr);
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif // CRYPTOPP_ALLOCATE_H
|
10333
wasm_src/codelift.cpp
Normal file
10333
wasm_src/codelift.cpp
Normal file
File diff suppressed because it is too large
Load Diff
8
wasm_src/codelift.h
Normal file
8
wasm_src/codelift.h
Normal file
@ -0,0 +1,8 @@
|
||||
#include <stdint.h>
|
||||
#include <emscripten/emscripten.h>
|
||||
extern "C" {
|
||||
EMSCRIPTEN_KEEPALIVE const char* guessInput(const char* input);
|
||||
EMSCRIPTEN_KEEPALIVE const char* getOutput(const char* input);
|
||||
EMSCRIPTEN_KEEPALIVE const char* getDeoaep(const char* input);
|
||||
EMSCRIPTEN_KEEPALIVE void freeStr(void* str);
|
||||
}
|
1253
wasm_src/config.h
Normal file
1253
wasm_src/config.h
Normal file
File diff suppressed because it is too large
Load Diff
1085
wasm_src/cpu.h
Normal file
1085
wasm_src/cpu.h
Normal file
File diff suppressed because it is too large
Load Diff
3349
wasm_src/cryptlib.h
Normal file
3349
wasm_src/cryptlib.h
Normal file
File diff suppressed because it is too large
Load Diff
1529
wasm_src/filters.h
Normal file
1529
wasm_src/filters.h
Normal file
File diff suppressed because it is too large
Load Diff
4648
wasm_src/integer.cpp
Normal file
4648
wasm_src/integer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
670
wasm_src/integer.h
Normal file
670
wasm_src/integer.h
Normal file
@ -0,0 +1,670 @@
|
||||
// integer.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file integer.h
|
||||
/// \brief Multiple precision integer with arithmetic operations
|
||||
/// \details The Integer class can represent positive and negative integers
|
||||
/// with absolute value less than (256**sizeof(word))<sup>(256**sizeof(int))</sup>.
|
||||
/// \details Internally, the library uses a sign magnitude representation, and the class
|
||||
/// has two data members. The first is a IntegerSecBlock (a SecBlock<word>) and it is
|
||||
/// used to hold the representation. The second is a Sign (an enumeration), and it is
|
||||
/// used to track the sign of the Integer.
|
||||
/// \details For details on how the Integer class initializes its function pointers using
|
||||
/// InitializeInteger and how it creates Integer::Zero(), Integer::One(), and
|
||||
/// Integer::Two(), then see the comments at the top of <tt>integer.cpp</tt>.
|
||||
/// \since Crypto++ 1.0
|
||||
|
||||
#ifndef CRYPTOPP_INTEGER_H
|
||||
#define CRYPTOPP_INTEGER_H
|
||||
|
||||
#include "cryptlib.h"
|
||||
#include "secblock.h"
|
||||
#include "stdcpp.h"
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
/// \struct InitializeInteger
|
||||
/// \brief Performs static initialization of the Integer class
|
||||
struct InitializeInteger
|
||||
{
|
||||
InitializeInteger();
|
||||
};
|
||||
|
||||
// Always align, http://github.com/weidai11/cryptopp/issues/256
|
||||
typedef SecBlock<word, AllocatorWithCleanup<word, true> > IntegerSecBlock;
|
||||
template class SecBlock<word, AllocatorWithCleanup<word, true> > ;
|
||||
/// \brief Multiple precision integer with arithmetic operations
|
||||
/// \details The Integer class can represent positive and negative integers
|
||||
/// with absolute value less than (256**sizeof(word))<sup>(256**sizeof(int))</sup>.
|
||||
/// \details Internally, the library uses a sign magnitude representation, and the class
|
||||
/// has two data members. The first is a IntegerSecBlock (a SecBlock<word>) and it is
|
||||
/// used to hold the representation. The second is a Sign (an enumeration), and it is
|
||||
/// used to track the sign of the Integer.
|
||||
/// \details For details on how the Integer class initializes its function pointers using
|
||||
/// InitializeInteger and how it creates Integer::Zero(), Integer::One(), and
|
||||
/// Integer::Two(), then see the comments at the top of <tt>integer.cpp</tt>.
|
||||
/// \since Crypto++ 1.0
|
||||
/// \nosubgrouping
|
||||
class CRYPTOPP_DLL Integer : private InitializeInteger
|
||||
{
|
||||
public:
|
||||
/// \name ENUMS, EXCEPTIONS, and TYPEDEFS
|
||||
//@{
|
||||
/// \brief Exception thrown when division by 0 is encountered
|
||||
class DivideByZero : public Exception
|
||||
{
|
||||
public:
|
||||
DivideByZero() : Exception(OTHER_ERROR, "Integer: division by zero") {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// \enum Sign
|
||||
/// \brief Used internally to represent the integer
|
||||
/// \details Sign is used internally to represent the integer. It is also used in a few API functions.
|
||||
/// \sa SetPositive(), SetNegative(), Signedness
|
||||
enum Sign {
|
||||
/// \brief the value is positive or 0
|
||||
POSITIVE=0,
|
||||
/// \brief the value is negative
|
||||
NEGATIVE=1};
|
||||
|
||||
/// \enum Signedness
|
||||
/// \brief Used when importing and exporting integers
|
||||
/// \details Signedness is usually used in API functions.
|
||||
/// \sa Sign
|
||||
enum Signedness {
|
||||
/// \brief an unsigned value
|
||||
UNSIGNED,
|
||||
/// \brief a signed value
|
||||
SIGNED};
|
||||
|
||||
|
||||
//@}
|
||||
|
||||
/// \name CREATORS
|
||||
//@{
|
||||
/// \brief Creates the zero integer
|
||||
Integer();
|
||||
|
||||
/// copy constructor
|
||||
Integer(const Integer& t);
|
||||
|
||||
/// \brief Convert from signed long
|
||||
Integer(signed long value);
|
||||
|
||||
/// \brief Convert from lword
|
||||
/// \param sign enumeration indicating Sign
|
||||
/// \param value the long word
|
||||
Integer(Sign sign, lword value);
|
||||
|
||||
/// \brief Convert from two words
|
||||
/// \param sign enumeration indicating Sign
|
||||
/// \param highWord the high word
|
||||
/// \param lowWord the low word
|
||||
Integer(Sign sign, word highWord, word lowWord);
|
||||
|
||||
/// \brief Convert from a C-string
|
||||
/// \param str C-string value
|
||||
/// \param order the ByteOrder of the string to be processed
|
||||
/// \details \p str can be in base 2, 8, 10, or 16. Base is determined by a case
|
||||
/// insensitive suffix of 'h', 'o', or 'b'. No suffix means base 10.
|
||||
/// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian
|
||||
/// integers with curve25519, Poly1305 and Microsoft CAPI.
|
||||
explicit Integer(const char *str, ByteOrder order = BIG_ENDIAN_ORDER);
|
||||
|
||||
/// \brief Convert from a wide C-string
|
||||
/// \param str wide C-string value
|
||||
/// \param order the ByteOrder of the string to be processed
|
||||
/// \details \p str can be in base 2, 8, 10, or 16. Base is determined by a case
|
||||
/// insensitive suffix of 'h', 'o', or 'b'. No suffix means base 10.
|
||||
/// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian
|
||||
/// integers with curve25519, Poly1305 and Microsoft CAPI.
|
||||
explicit Integer(const wchar_t *str, ByteOrder order = BIG_ENDIAN_ORDER);
|
||||
|
||||
/// \brief Convert from a big-endian byte array
|
||||
/// \param encodedInteger big-endian byte array
|
||||
/// \param byteCount length of the byte array
|
||||
/// \param sign enumeration indicating Signedness
|
||||
/// \param order the ByteOrder of the array to be processed
|
||||
/// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian
|
||||
/// integers with curve25519, Poly1305 and Microsoft CAPI.
|
||||
Integer(const byte *encodedInteger, size_t byteCount, Signedness sign=UNSIGNED, ByteOrder order = BIG_ENDIAN_ORDER);
|
||||
|
||||
/// \brief Convert from a big-endian array
|
||||
/// \param bt BufferedTransformation object with big-endian byte array
|
||||
/// \param byteCount length of the byte array
|
||||
/// \param sign enumeration indicating Signedness
|
||||
/// \param order the ByteOrder of the data to be processed
|
||||
/// \details Byte order was added at Crypto++ 5.7 to allow use of little-endian
|
||||
/// integers with curve25519, Poly1305 and Microsoft CAPI.
|
||||
Integer(BufferedTransformation &bt, size_t byteCount, Signedness sign=UNSIGNED, ByteOrder order = BIG_ENDIAN_ORDER);
|
||||
|
||||
|
||||
/// \brief Integer representing 0
|
||||
/// \return an Integer representing 0
|
||||
/// \details Zero() avoids calling constructors for frequently used integers
|
||||
static const Integer & CRYPTOPP_API Zero();
|
||||
/// \brief Integer representing 1
|
||||
/// \return an Integer representing 1
|
||||
/// \details One() avoids calling constructors for frequently used integers
|
||||
static const Integer & CRYPTOPP_API One();
|
||||
/// \brief Integer representing 2
|
||||
/// \return an Integer representing 2
|
||||
/// \details Two() avoids calling constructors for frequently used integers
|
||||
static const Integer & CRYPTOPP_API Two();
|
||||
|
||||
|
||||
/// \brief Exponentiates to a power of 2
|
||||
/// \return the Integer 2<sup>e</sup>
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
static Integer CRYPTOPP_API Power2(size_t e);
|
||||
//@}
|
||||
|
||||
/// \name ENCODE/DECODE
|
||||
//@{
|
||||
/// \brief Minimum number of bytes to encode this integer
|
||||
/// \param sign enumeration indicating Signedness
|
||||
/// \note The MinEncodedSize() of 0 is 1.
|
||||
size_t MinEncodedSize(Signedness sign=UNSIGNED) const;
|
||||
|
||||
/// \brief Encode in big-endian format
|
||||
/// \param output big-endian byte array
|
||||
/// \param outputLen length of the byte array
|
||||
/// \param sign enumeration indicating Signedness
|
||||
/// \details Unsigned means encode absolute value, signed means encode two's complement if negative.
|
||||
/// \details outputLen can be used to ensure an Integer is encoded to an exact size (rather than a
|
||||
/// minimum size). An exact size is useful, for example, when encoding to a field element size.
|
||||
void Encode(byte *output, size_t outputLen, Signedness sign=UNSIGNED) const;
|
||||
|
||||
|
||||
|
||||
/// \brief Decode from big-endian byte array
|
||||
/// \param input big-endian byte array
|
||||
/// \param inputLen length of the byte array
|
||||
/// \param sign enumeration indicating Signedness
|
||||
void Decode(const byte *input, size_t inputLen, Signedness sign=UNSIGNED);
|
||||
|
||||
/// \brief Decode nonnegative value from big-endian byte array
|
||||
/// \param bt BufferedTransformation object
|
||||
/// \param inputLen length of the byte array
|
||||
/// \param sign enumeration indicating Signedness
|
||||
/// \note <tt>bt.MaxRetrievable() \>= inputLen</tt>.
|
||||
void Decode(BufferedTransformation &bt, size_t inputLen, Signedness sign=UNSIGNED);
|
||||
|
||||
|
||||
//@}
|
||||
|
||||
/// \name ACCESSORS
|
||||
//@{
|
||||
/// \brief Determines if the Integer is convertable to Long
|
||||
/// \return true if *this can be represented as a signed long
|
||||
/// \sa ConvertToLong()
|
||||
bool IsConvertableToLong() const;
|
||||
/// \brief Convert the Integer to Long
|
||||
/// \return equivalent signed long if possible, otherwise undefined
|
||||
/// \sa IsConvertableToLong()
|
||||
signed long ConvertToLong() const;
|
||||
|
||||
/// \brief Determines the number of bits required to represent the Integer
|
||||
/// \return number of significant bits
|
||||
/// \details BitCount is calculated as <tt>floor(log2(abs(*this))) + 1</tt>.
|
||||
unsigned int BitCount() const;
|
||||
/// \brief Determines the number of bytes required to represent the Integer
|
||||
/// \return number of significant bytes
|
||||
/// \details ByteCount is calculated as <tt>ceiling(BitCount()/8)</tt>.
|
||||
unsigned int ByteCount() const;
|
||||
/// \brief Determines the number of words required to represent the Integer
|
||||
/// \return number of significant words
|
||||
/// \details WordCount is calculated as <tt>ceiling(ByteCount()/sizeof(word))</tt>.
|
||||
unsigned int WordCount() const;
|
||||
|
||||
/// \brief Provides the i-th bit of the Integer
|
||||
/// \return the i-th bit, i=0 being the least significant bit
|
||||
bool GetBit(size_t i) const;
|
||||
/// \brief Provides the i-th byte of the Integer
|
||||
/// \return the i-th byte
|
||||
byte GetByte(size_t i) const;
|
||||
/// \brief Provides the low order bits of the Integer
|
||||
/// \return n lowest bits of *this >> i
|
||||
lword GetBits(size_t i, size_t n) const;
|
||||
|
||||
/// \brief Determines if the Integer is 0
|
||||
/// \return true if the Integer is 0, false otherwise
|
||||
bool IsZero() const {return !*this;}
|
||||
/// \brief Determines if the Integer is non-0
|
||||
/// \return true if the Integer is non-0, false otherwise
|
||||
bool NotZero() const {return !IsZero();}
|
||||
/// \brief Determines if the Integer is negative
|
||||
/// \return true if the Integer is negative, false otherwise
|
||||
bool IsNegative() const {return sign == NEGATIVE;}
|
||||
/// \brief Determines if the Integer is non-negative
|
||||
/// \return true if the Integer is non-negative, false otherwise
|
||||
bool NotNegative() const {return !IsNegative();}
|
||||
/// \brief Determines if the Integer is positive
|
||||
/// \return true if the Integer is positive, false otherwise
|
||||
bool IsPositive() const {return NotNegative() && NotZero();}
|
||||
/// \brief Determines if the Integer is non-positive
|
||||
/// \return true if the Integer is non-positive, false otherwise
|
||||
bool NotPositive() const {return !IsPositive();}
|
||||
/// \brief Determines if the Integer is even parity
|
||||
/// \return true if the Integer is even, false otherwise
|
||||
bool IsEven() const {return GetBit(0) == 0;}
|
||||
/// \brief Determines if the Integer is odd parity
|
||||
/// \return true if the Integer is odd, false otherwise
|
||||
bool IsOdd() const {return GetBit(0) == 1;}
|
||||
//@}
|
||||
|
||||
/// \name MANIPULATORS
|
||||
//@{
|
||||
/// \brief Assignment
|
||||
/// \param t the other Integer
|
||||
/// \return the result of assignment
|
||||
Integer& operator=(const Integer& t);
|
||||
/// \brief Addition Assignment
|
||||
/// \param t the other Integer
|
||||
/// \return the result of <tt>*this + t</tt>
|
||||
Integer& operator+=(const Integer& t);
|
||||
/// \brief Subtraction Assignment
|
||||
/// \param t the other Integer
|
||||
/// \return the result of <tt>*this - t</tt>
|
||||
Integer& operator-=(const Integer& t);
|
||||
/// \brief Multiplication Assignment
|
||||
/// \param t the other Integer
|
||||
/// \return the result of <tt>*this * t</tt>
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
Integer& operator*=(const Integer& t) {return *this = Times(t);}
|
||||
/// \brief Division Assignment
|
||||
/// \param t the other Integer
|
||||
/// \return the result of <tt>*this / t</tt>
|
||||
Integer& operator/=(const Integer& t) {return *this = DividedBy(t);}
|
||||
/// \brief Remainder Assignment
|
||||
/// \param t the other Integer
|
||||
/// \return the result of <tt>*this % t</tt>
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
Integer& operator%=(const Integer& t) {return *this = Modulo(t);}
|
||||
/// \brief Division Assignment
|
||||
/// \param t the other word
|
||||
/// \return the result of <tt>*this / t</tt>
|
||||
Integer& operator/=(word t) {return *this = DividedBy(t);}
|
||||
/// \brief Remainder Assignment
|
||||
/// \param t the other word
|
||||
/// \return the result of <tt>*this % t</tt>
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
Integer& operator%=(word t) {return *this = Integer(POSITIVE, 0, Modulo(t));}
|
||||
|
||||
/// \brief Left-shift Assignment
|
||||
/// \param n number of bits to shift
|
||||
/// \return reference to this Integer
|
||||
Integer& operator<<=(size_t n);
|
||||
/// \brief Right-shift Assignment
|
||||
/// \param n number of bits to shift
|
||||
/// \return reference to this Integer
|
||||
Integer& operator>>=(size_t n);
|
||||
|
||||
/// \brief Bitwise AND Assignment
|
||||
/// \param t the other Integer
|
||||
/// \return the result of *this & t
|
||||
/// \details operator&=() performs a bitwise AND on *this. Missing bits are truncated
|
||||
/// at the most significant bit positions, so the result is as small as the
|
||||
/// smaller of the operands.
|
||||
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
|
||||
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
|
||||
/// the integer should be converted to a 2's compliment representation before performing
|
||||
/// the operation.
|
||||
/// \since Crypto++ 6.0
|
||||
Integer& operator&=(const Integer& t);
|
||||
/// \brief Bitwise OR Assignment
|
||||
/// \param t the second Integer
|
||||
/// \return the result of *this | t
|
||||
/// \details operator|=() performs a bitwise OR on *this. Missing bits are shifted in
|
||||
/// at the most significant bit positions, so the result is as large as the
|
||||
/// larger of the operands.
|
||||
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
|
||||
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
|
||||
/// the integer should be converted to a 2's compliment representation before performing
|
||||
/// the operation.
|
||||
/// \since Crypto++ 6.0
|
||||
Integer& operator|=(const Integer& t);
|
||||
/// \brief Bitwise XOR Assignment
|
||||
/// \param t the other Integer
|
||||
/// \return the result of *this ^ t
|
||||
/// \details operator^=() performs a bitwise XOR on *this. Missing bits are shifted
|
||||
/// in at the most significant bit positions, so the result is as large as the
|
||||
/// larger of the operands.
|
||||
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
|
||||
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
|
||||
/// the integer should be converted to a 2's compliment representation before performing
|
||||
/// the operation.
|
||||
/// \since Crypto++ 6.0
|
||||
Integer& operator^=(const Integer& t);
|
||||
|
||||
|
||||
|
||||
/// \brief Set the n-th bit to value
|
||||
/// \details 0-based numbering.
|
||||
void SetBit(size_t n, bool value=1);
|
||||
|
||||
/// \brief Set the n-th byte to value
|
||||
/// \details 0-based numbering.
|
||||
void SetByte(size_t n, byte value);
|
||||
|
||||
/// \brief Reverse the Sign of the Integer
|
||||
void Negate();
|
||||
|
||||
/// \brief Sets the Integer to positive
|
||||
void SetPositive() {sign = POSITIVE;}
|
||||
|
||||
/// \brief Sets the Integer to negative
|
||||
void SetNegative() {if (!!(*this)) sign = NEGATIVE;}
|
||||
|
||||
/// \brief Swaps this Integer with another Integer
|
||||
void swap(Integer &a);
|
||||
//@}
|
||||
|
||||
/// \name UNARY OPERATORS
|
||||
//@{
|
||||
/// \brief Negation
|
||||
bool operator!() const;
|
||||
/// \brief Addition
|
||||
Integer operator+() const {return *this;}
|
||||
/// \brief Subtraction
|
||||
Integer operator-() const;
|
||||
/// \brief Pre-increment
|
||||
Integer& operator++();
|
||||
/// \brief Pre-decrement
|
||||
Integer& operator--();
|
||||
/// \brief Post-increment
|
||||
Integer operator++(int) {Integer temp = *this; ++*this; return temp;}
|
||||
/// \brief Post-decrement
|
||||
Integer operator--(int) {Integer temp = *this; --*this; return temp;}
|
||||
//@}
|
||||
|
||||
/// \name BINARY OPERATORS
|
||||
//@{
|
||||
/// \brief Perform signed comparison
|
||||
/// \param a the Integer to comapre
|
||||
/// \retval -1 if <tt>*this < a</tt>
|
||||
/// \retval 0 if <tt>*this = a</tt>
|
||||
/// \retval 1 if <tt>*this > a</tt>
|
||||
int Compare(const Integer& a) const;
|
||||
|
||||
/// \brief Addition
|
||||
Integer Plus(const Integer &b) const;
|
||||
/// \brief Subtraction
|
||||
Integer Minus(const Integer &b) const;
|
||||
/// \brief Multiplication
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
Integer Times(const Integer &b) const;
|
||||
/// \brief Division
|
||||
Integer DividedBy(const Integer &b) const;
|
||||
/// \brief Remainder
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
Integer Modulo(const Integer &b) const;
|
||||
/// \brief Division
|
||||
Integer DividedBy(word b) const;
|
||||
/// \brief Remainder
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
word Modulo(word b) const;
|
||||
|
||||
/// \brief Bitwise AND
|
||||
/// \param t the other Integer
|
||||
/// \return the result of <tt>*this & t</tt>
|
||||
/// \details And() performs a bitwise AND on the operands. Missing bits are truncated
|
||||
/// at the most significant bit positions, so the result is as small as the
|
||||
/// smaller of the operands.
|
||||
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
|
||||
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
|
||||
/// the integer should be converted to a 2's compliment representation before performing
|
||||
/// the operation.
|
||||
/// \since Crypto++ 6.0
|
||||
Integer And(const Integer& t) const;
|
||||
|
||||
/// \brief Bitwise OR
|
||||
/// \param t the other Integer
|
||||
/// \return the result of <tt>*this | t</tt>
|
||||
/// \details Or() performs a bitwise OR on the operands. Missing bits are shifted in
|
||||
/// at the most significant bit positions, so the result is as large as the
|
||||
/// larger of the operands.
|
||||
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
|
||||
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
|
||||
/// the integer should be converted to a 2's compliment representation before performing
|
||||
/// the operation.
|
||||
/// \since Crypto++ 6.0
|
||||
Integer Or(const Integer& t) const;
|
||||
|
||||
/// \brief Bitwise XOR
|
||||
/// \param t the other Integer
|
||||
/// \return the result of <tt>*this ^ t</tt>
|
||||
/// \details Xor() performs a bitwise XOR on the operands. Missing bits are shifted in
|
||||
/// at the most significant bit positions, so the result is as large as the
|
||||
/// larger of the operands.
|
||||
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
|
||||
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
|
||||
/// the integer should be converted to a 2's compliment representation before performing
|
||||
/// the operation.
|
||||
/// \since Crypto++ 6.0
|
||||
Integer Xor(const Integer& t) const;
|
||||
|
||||
/// \brief Right-shift
|
||||
Integer operator>>(size_t n) const {return Integer(*this)>>=n;}
|
||||
/// \brief Left-shift
|
||||
Integer operator<<(size_t n) const {return Integer(*this)<<=n;}
|
||||
//@}
|
||||
|
||||
/// \name OTHER ARITHMETIC FUNCTIONS
|
||||
//@{
|
||||
/// \brief Retrieve the absolute value of this integer
|
||||
Integer AbsoluteValue() const;
|
||||
/// \brief Add this integer to itself
|
||||
Integer Doubled() const {return Plus(*this);}
|
||||
/// \brief Multiply this integer by itself
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
Integer Squared() const {return Times(*this);}
|
||||
/// \brief Extract square root
|
||||
/// \details if negative return 0, else return floor of square root
|
||||
Integer SquareRoot() const;
|
||||
/// \brief Determine whether this integer is a perfect square
|
||||
bool IsSquare() const;
|
||||
|
||||
/// \brief Determine if 1 or -1
|
||||
/// \return true if this integer is 1 or -1, false otherwise
|
||||
bool IsUnit() const;
|
||||
/// \brief Calculate multiplicative inverse
|
||||
/// \return MultiplicativeInverse inverse if 1 or -1, otherwise return 0.
|
||||
Integer MultiplicativeInverse() const;
|
||||
|
||||
/// \brief Extended Division
|
||||
/// \param r a reference for the remainder
|
||||
/// \param q a reference for the quotient
|
||||
/// \param a a reference to the dividend
|
||||
/// \param d a reference to the divisor
|
||||
/// \details Divide calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)).
|
||||
static void CRYPTOPP_API Divide(Integer &r, Integer &q, const Integer &a, const Integer &d);
|
||||
|
||||
/// \brief Extended Division
|
||||
/// \param r a reference for the remainder
|
||||
/// \param q a reference for the quotient
|
||||
/// \param a a reference to the dividend
|
||||
/// \param d a reference to the divisor
|
||||
/// \details Divide calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)).
|
||||
/// This overload uses a faster division algorithm because the divisor is short.
|
||||
static void CRYPTOPP_API Divide(word &r, Integer &q, const Integer &a, word d);
|
||||
|
||||
/// \brief Extended Division
|
||||
/// \param r a reference for the remainder
|
||||
/// \param q a reference for the quotient
|
||||
/// \param a a reference to the dividend
|
||||
/// \param n a reference to the divisor
|
||||
/// \details DivideByPowerOf2 calculates r and q such that (a == d*q + r) && (0 <= r < abs(d)).
|
||||
/// It returns same result as Divide(r, q, a, Power2(n)), but faster.
|
||||
/// This overload uses a faster division algorithm because the divisor is a power of 2.
|
||||
static void CRYPTOPP_API DivideByPowerOf2(Integer &r, Integer &q, const Integer &a, unsigned int n);
|
||||
|
||||
/// \brief Calculate greatest common divisor
|
||||
/// \param a a reference to the first number
|
||||
/// \param n a reference to the secind number
|
||||
/// \return the greatest common divisor <tt>a</tt> and <tt>n</tt>.
|
||||
static Integer CRYPTOPP_API Gcd(const Integer &a, const Integer &n);
|
||||
|
||||
/// \brief Calculate multiplicative inverse
|
||||
/// \param n a reference to the modulus
|
||||
/// \return an Integer <tt>*this % n</tt>.
|
||||
/// \details InverseMod returns the multiplicative inverse of the Integer <tt>*this</tt>
|
||||
/// modulo the Integer <tt>n</tt>. If no Integer exists then Integer 0 is returned.
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
Integer InverseMod(const Integer &n) const;
|
||||
|
||||
/// \brief Calculate multiplicative inverse
|
||||
/// \param n the modulus
|
||||
/// \return a word <tt>*this % n</tt>.
|
||||
/// \details InverseMod returns the multiplicative inverse of the Integer <tt>*this</tt>
|
||||
/// modulo the word <tt>n</tt>. If no Integer exists then word 0 is returned.
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
word InverseMod(word n) const;
|
||||
//@}
|
||||
|
||||
/// \name INPUT/OUTPUT
|
||||
//@{
|
||||
/// \brief Extraction operator
|
||||
/// \param in a reference to a std::istream
|
||||
/// \param a a reference to an Integer
|
||||
/// \return a reference to a std::istream reference
|
||||
friend CRYPTOPP_DLL std::istream& CRYPTOPP_API operator>>(std::istream& in, Integer &a);
|
||||
|
||||
/// \brief Insertion operator
|
||||
/// \param out a reference to a std::ostream
|
||||
/// \param a a constant reference to an Integer
|
||||
/// \return a reference to a std::ostream reference
|
||||
/// \details The output integer responds to std::hex, std::oct, std::hex, std::upper and
|
||||
/// std::lower. The output includes the suffix \a h (for hex), \a . (\a dot, for dec)
|
||||
/// and \a o (for octal). There is currently no way to suppress the suffix.
|
||||
/// \details If you want to print an Integer without the suffix or using an arbitrary base, then
|
||||
/// use IntToString<Integer>().
|
||||
/// \sa IntToString<Integer>
|
||||
friend CRYPTOPP_DLL std::ostream& CRYPTOPP_API operator<<(std::ostream& out, const Integer &a);
|
||||
//@}
|
||||
|
||||
/// \brief Modular multiplication
|
||||
/// \param x a reference to the first term
|
||||
/// \param y a reference to the second term
|
||||
/// \param m a reference to the modulus
|
||||
/// \return an Integer <tt>(a * b) % m</tt>.
|
||||
CRYPTOPP_DLL friend Integer CRYPTOPP_API a_times_b_mod_c(const Integer &x, const Integer& y, const Integer& m);
|
||||
/// \brief Modular exponentiation
|
||||
/// \param x a reference to the base
|
||||
/// \param e a reference to the exponent
|
||||
/// \param m a reference to the modulus
|
||||
/// \return an Integer <tt>(a ^ b) % m</tt>.
|
||||
CRYPTOPP_DLL friend Integer CRYPTOPP_API a_exp_b_mod_c(const Integer &x, const Integer& e, const Integer& m);
|
||||
|
||||
protected:
|
||||
|
||||
// http://github.com/weidai11/cryptopp/issues/602
|
||||
Integer InverseModNext(const Integer &n) const;
|
||||
|
||||
private:
|
||||
|
||||
Integer(word value, size_t length);
|
||||
int PositiveCompare(const Integer &t) const;
|
||||
|
||||
IntegerSecBlock reg;
|
||||
Sign sign;
|
||||
|
||||
#ifndef CRYPTOPP_DOXYGEN_PROCESSING
|
||||
friend class ModularArithmetic;
|
||||
friend class MontgomeryRepresentation;
|
||||
friend class HalfMontgomeryRepresentation;
|
||||
|
||||
friend void PositiveAdd(Integer &sum, const Integer &a, const Integer &b);
|
||||
friend void PositiveSubtract(Integer &diff, const Integer &a, const Integer &b);
|
||||
friend void PositiveMultiply(Integer &product, const Integer &a, const Integer &b);
|
||||
friend void PositiveDivide(Integer &remainder, Integer "ient, const Integer ÷nd, const Integer &divisor);
|
||||
#endif
|
||||
};
|
||||
|
||||
/// \brief Comparison
|
||||
inline bool operator==(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)==0;}
|
||||
/// \brief Comparison
|
||||
inline bool operator!=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)!=0;}
|
||||
/// \brief Comparison
|
||||
inline bool operator> (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)> 0;}
|
||||
/// \brief Comparison
|
||||
inline bool operator>=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)>=0;}
|
||||
/// \brief Comparison
|
||||
inline bool operator< (const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)< 0;}
|
||||
/// \brief Comparison
|
||||
inline bool operator<=(const CryptoPP::Integer& a, const CryptoPP::Integer& b) {return a.Compare(b)<=0;}
|
||||
/// \brief Addition
|
||||
inline CryptoPP::Integer operator+(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Plus(b);}
|
||||
/// \brief Subtraction
|
||||
inline CryptoPP::Integer operator-(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Minus(b);}
|
||||
/// \brief Multiplication
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
inline CryptoPP::Integer operator*(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Times(b);}
|
||||
/// \brief Division
|
||||
inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.DividedBy(b);}
|
||||
/// \brief Remainder
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
inline CryptoPP::Integer operator%(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Modulo(b);}
|
||||
/// \brief Division
|
||||
inline CryptoPP::Integer operator/(const CryptoPP::Integer &a, CryptoPP::word b) {return a.DividedBy(b);}
|
||||
/// \brief Remainder
|
||||
/// \sa a_times_b_mod_c() and a_exp_b_mod_c()
|
||||
inline CryptoPP::word operator%(const CryptoPP::Integer &a, CryptoPP::word b) {return a.Modulo(b);}
|
||||
|
||||
/// \brief Bitwise AND
|
||||
/// \param a the first Integer
|
||||
/// \param b the second Integer
|
||||
/// \return the result of a & b
|
||||
/// \details operator&() performs a bitwise AND on the operands. Missing bits are truncated
|
||||
/// at the most significant bit positions, so the result is as small as the
|
||||
/// smaller of the operands.
|
||||
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
|
||||
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
|
||||
/// the integer should be converted to a 2's compliment representation before performing
|
||||
/// the operation.
|
||||
/// \since Crypto++ 6.0
|
||||
inline CryptoPP::Integer operator&(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.And(b);}
|
||||
|
||||
/// \brief Bitwise OR
|
||||
/// \param a the first Integer
|
||||
/// \param b the second Integer
|
||||
/// \return the result of a | b
|
||||
/// \details operator|() performs a bitwise OR on the operands. Missing bits are shifted in
|
||||
/// at the most significant bit positions, so the result is as large as the
|
||||
/// larger of the operands.
|
||||
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
|
||||
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
|
||||
/// the integer should be converted to a 2's compliment representation before performing
|
||||
/// the operation.
|
||||
/// \since Crypto++ 6.0
|
||||
inline CryptoPP::Integer operator|(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Or(b);}
|
||||
|
||||
/// \brief Bitwise XOR
|
||||
/// \param a the first Integer
|
||||
/// \param b the second Integer
|
||||
/// \return the result of a ^ b
|
||||
/// \details operator^() performs a bitwise XOR on the operands. Missing bits are shifted
|
||||
/// in at the most significant bit positions, so the result is as large as the
|
||||
/// larger of the operands.
|
||||
/// \details Internally, Crypto++ uses a sign-magnitude representation. The library
|
||||
/// does not attempt to interpret bits, and the result is always POSITIVE. If needed,
|
||||
/// the integer should be converted to a 2's compliment representation before performing
|
||||
/// the operation.
|
||||
/// \since Crypto++ 6.0
|
||||
inline CryptoPP::Integer operator^(const CryptoPP::Integer &a, const CryptoPP::Integer &b) {return a.Xor(b);}
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#ifndef __BORLANDC__
|
||||
NAMESPACE_BEGIN(std)
|
||||
inline void swap(CryptoPP::Integer &a, CryptoPP::Integer &b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
NAMESPACE_END
|
||||
#endif
|
||||
|
||||
#endif
|
669
wasm_src/longconsts.h
Normal file
669
wasm_src/longconsts.h
Normal file
File diff suppressed because one or more lines are too long
393
wasm_src/misc.cpp
Normal file
393
wasm_src/misc.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
// misc.cpp - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
#include "pch.h"
|
||||
#include "config.h"
|
||||
|
||||
#if CRYPTOPP_MSC_VERSION
|
||||
# pragma warning(disable: 4189)
|
||||
# if (CRYPTOPP_MSC_VERSION >= 1400)
|
||||
# pragma warning(disable: 6237)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef CRYPTOPP_IMPORTS
|
||||
|
||||
#include "misc.h"
|
||||
#include "words.h"
|
||||
#include "stdcpp.h"
|
||||
#include "integer.h"
|
||||
#include "secblock.h"
|
||||
|
||||
// Hack for OpenBSD and GCC 4.2.1. I believe they are stuck at 4.2.1 due to GPLv3.
|
||||
#if defined(__OpenBSD__)
|
||||
# if defined (CRYPTOPP_GCC_VERSION) && (CRYPTOPP_GCC_VERSION < 43000)
|
||||
# undef CRYPTOPP_DISABLE_ASM
|
||||
# define CRYPTOPP_DISABLE_ASM 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef CRYPTOPP_DISABLE_ASM
|
||||
# if defined(__SSE2__)
|
||||
# include <emmintrin.h>
|
||||
# endif
|
||||
# if defined(__AVX__)
|
||||
# include <immintrin.h>
|
||||
# endif
|
||||
|
||||
# if defined(__aarch64__) || defined(__aarch32__) || defined(_M_ARM64)
|
||||
# if defined(CRYPTOPP_ARM_NEON_HEADER)
|
||||
# include <arm_neon.h>
|
||||
# endif
|
||||
# endif
|
||||
#endif // CRYPTOPP_DISABLE_ASM
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
byte* BytePtr(SecByteBlock& str)
|
||||
{
|
||||
// Caller wants a writeable pointer
|
||||
CRYPTOPP_ASSERT(str.empty() == false);
|
||||
|
||||
if (str.empty())
|
||||
return NULLPTR;
|
||||
return reinterpret_cast<byte*>(str.data());
|
||||
}
|
||||
|
||||
const byte* ConstBytePtr(const SecByteBlock& str)
|
||||
{
|
||||
if (str.empty())
|
||||
return NULLPTR;
|
||||
return reinterpret_cast<const byte*>(str.data());
|
||||
}
|
||||
|
||||
size_t BytePtrSize(const SecByteBlock& str)
|
||||
{
|
||||
return str.size();
|
||||
}
|
||||
|
||||
// xorbuf simplified at https://github.com/weidai11/cryptopp/issues/1020
|
||||
void xorbuf(byte *buf, const byte *mask, size_t count)
|
||||
{
|
||||
CRYPTOPP_ASSERT(buf != NULLPTR);
|
||||
CRYPTOPP_ASSERT(mask != NULLPTR);
|
||||
CRYPTOPP_ASSERT(count > 0);
|
||||
|
||||
#ifndef CRYPTOPP_DISABLE_ASM
|
||||
# if defined(__AVX__)
|
||||
while (count >= 32)
|
||||
{
|
||||
__m256i b = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(buf));
|
||||
__m256i m = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(mask));
|
||||
_mm256_storeu_si256(reinterpret_cast<__m256i*>(buf), _mm256_castps_si256(
|
||||
_mm256_xor_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(m))));
|
||||
buf += 32; mask += 32; count -= 32;
|
||||
}
|
||||
// https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties
|
||||
_mm256_zeroupper();
|
||||
# endif
|
||||
# if defined(__SSE2__)
|
||||
while (count >= 16)
|
||||
{
|
||||
__m128i b = _mm_loadu_si128(reinterpret_cast<const __m128i*>(buf));
|
||||
__m128i m = _mm_loadu_si128(reinterpret_cast<const __m128i*>(mask));
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(buf), _mm_castps_si128(
|
||||
_mm_xor_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(m))));
|
||||
buf += 16; mask += 16; count -= 16;
|
||||
}
|
||||
# endif
|
||||
# if defined(__aarch64__) || defined(__aarch32__) || defined(_M_ARM64)
|
||||
while (count >= 16)
|
||||
{
|
||||
vst1q_u8(buf, veorq_u8(vld1q_u8(buf), vld1q_u8(mask)));
|
||||
buf += 16; mask += 16; count -= 16;
|
||||
}
|
||||
# endif
|
||||
#endif // CRYPTOPP_DISABLE_ASM
|
||||
|
||||
#if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64
|
||||
// word64 and stride of 8 slows things down on x86_64.
|
||||
// word64 and stride of 8 makes no difference on ARM.
|
||||
// word64 and stride of 16 benefits PowerPC.
|
||||
while (count >= 16)
|
||||
{
|
||||
word64 r[2], b[2], m[2];
|
||||
memcpy(&b, buf, 16); memcpy(&m, mask, 16);
|
||||
|
||||
r[0] = b[0] ^ m[0];
|
||||
r[1] = b[1] ^ m[1];
|
||||
memcpy(buf, &r, 16);
|
||||
|
||||
buf += 16; mask += 16; count -= 16;
|
||||
}
|
||||
#endif
|
||||
|
||||
// One of the arch specific xor's may have cleared the request
|
||||
if (count == 0) return;
|
||||
|
||||
while (count >= 4)
|
||||
{
|
||||
word32 r, b, m;
|
||||
memcpy(&b, buf, 4); memcpy(&m, mask, 4);
|
||||
|
||||
r = b ^ m;
|
||||
memcpy(buf, &r, 4);
|
||||
|
||||
buf += 4; mask += 4; count -= 4;
|
||||
}
|
||||
|
||||
for (size_t i=0; i<count; i++)
|
||||
buf[i] ^= mask[i];
|
||||
}
|
||||
|
||||
// xorbuf simplified at https://github.com/weidai11/cryptopp/issues/1020
|
||||
void xorbuf(byte *output, const byte *input, const byte *mask, size_t count)
|
||||
{
|
||||
CRYPTOPP_ASSERT(output != NULLPTR);
|
||||
CRYPTOPP_ASSERT(input != NULLPTR);
|
||||
CRYPTOPP_ASSERT(count > 0);
|
||||
|
||||
#ifndef CRYPTOPP_DISABLE_ASM
|
||||
# if defined(__AVX__)
|
||||
while (count >= 32)
|
||||
{
|
||||
__m256i b = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(input));
|
||||
__m256i m = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(mask));
|
||||
_mm256_storeu_si256(reinterpret_cast<__m256i*>(output), _mm256_castps_si256(
|
||||
_mm256_xor_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(m))));
|
||||
output += 32; input += 32; mask += 32; count -= 32;
|
||||
}
|
||||
// https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties
|
||||
_mm256_zeroupper();
|
||||
# endif
|
||||
# if defined(__SSE2__)
|
||||
while (count >= 16)
|
||||
{
|
||||
__m128i b = _mm_loadu_si128(reinterpret_cast<const __m128i*>(input));
|
||||
__m128i m = _mm_loadu_si128(reinterpret_cast<const __m128i*>(mask));
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(output), _mm_castps_si128(
|
||||
_mm_xor_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(m))));
|
||||
output += 16; input += 16; mask += 16; count -= 16;
|
||||
}
|
||||
# endif
|
||||
# if defined(__aarch64__) || defined(__aarch32__) || defined(_M_ARM64)
|
||||
while (count >= 16)
|
||||
{
|
||||
vst1q_u8(output, veorq_u8(vld1q_u8(input), vld1q_u8(mask)));
|
||||
output += 16; input += 16; mask += 16; count -= 16;
|
||||
}
|
||||
# endif
|
||||
#endif // CRYPTOPP_DISABLE_ASM
|
||||
|
||||
#if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64
|
||||
// word64 and stride of 8 slows things down on x86_64.
|
||||
// word64 and stride of 8 makes no difference on ARM.
|
||||
// word64 and stride of 16 benefits PowerPC.
|
||||
while (count >= 16)
|
||||
{
|
||||
word64 b[2], m[2], r[2];
|
||||
memcpy(&b, input, 16); memcpy(&m, mask, 16);
|
||||
|
||||
r[0] = b[0] ^ m[0];
|
||||
r[1] = b[1] ^ m[1];
|
||||
memcpy(output, &r, 16);
|
||||
|
||||
output += 16; input += 16; mask += 16; count -= 16;
|
||||
}
|
||||
#endif
|
||||
|
||||
// One of the arch specific xor's may have cleared the request
|
||||
if (count == 0) return;
|
||||
|
||||
while (count >= 4)
|
||||
{
|
||||
word32 b, m, r;
|
||||
memcpy(&b, input, 4); memcpy(&m, mask, 4);
|
||||
|
||||
r = b ^ m;
|
||||
memcpy(output, &r, 4);
|
||||
|
||||
output += 4; input += 4; mask += 4; count -= 4;
|
||||
}
|
||||
|
||||
for (size_t i=0; i<count; i++)
|
||||
output[i] = input[i] ^ mask[i];
|
||||
}
|
||||
|
||||
// VerifyBufsEqual simplified at https://github.com/weidai11/cryptopp/issues/1020
|
||||
bool VerifyBufsEqual(const byte *buf, const byte *mask, size_t count)
|
||||
{
|
||||
CRYPTOPP_ASSERT(buf != NULLPTR);
|
||||
CRYPTOPP_ASSERT(mask != NULLPTR);
|
||||
// CRYPTOPP_ASSERT(count > 0);
|
||||
|
||||
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_ARM64 || CRYPTOPP_BOOL_PPC64 || CRYPTOPP_BOOL_MIPS64 || CRYPTOPP_BOOL_SPARC64
|
||||
word64 acc64 = 0;
|
||||
while (count >= 8)
|
||||
{
|
||||
word64 b, m;
|
||||
memcpy(&b, buf, 8); memcpy(&m, mask, 8);
|
||||
acc64 |= b ^ m;
|
||||
|
||||
buf += 8; mask += 8; count -= 8;
|
||||
}
|
||||
|
||||
word32 acc8 = (acc64 >> 32) | (acc64 & 0xffffffff);
|
||||
acc8 = static_cast<byte>(acc8) | static_cast<byte>(acc8 >> 8) |
|
||||
static_cast<byte>(acc8 >> 16) | static_cast<byte>(acc8 >> 24);
|
||||
#else
|
||||
word32 acc32 = 0;
|
||||
while (count >= 4)
|
||||
{
|
||||
word32 b, m;
|
||||
memcpy(&b, buf, 4); memcpy(&m, mask, 4);
|
||||
acc32 |= b ^ m;
|
||||
|
||||
buf += 4; mask += 4; count -= 4;
|
||||
}
|
||||
|
||||
word32 acc8 = acc32;
|
||||
acc8 = static_cast<byte>(acc8) | static_cast<byte>(acc8 >> 8) |
|
||||
static_cast<byte>(acc8 >> 16) | static_cast<byte>(acc8 >> 24);
|
||||
#endif
|
||||
|
||||
for (size_t i=0; i<count; i++)
|
||||
acc8 |= buf[i] ^ mask[i];
|
||||
|
||||
// word32 resuts in this tail code on x86:
|
||||
// 33a: 85 c0 test %eax, %eax
|
||||
// 33c: 0f 94 c0 sete %al
|
||||
// 33f: c3 ret
|
||||
return acc8 == 0;
|
||||
}
|
||||
|
||||
std::string StringNarrow(const wchar_t *str, bool throwOnError)
|
||||
{
|
||||
CRYPTOPP_ASSERT(str);
|
||||
std::string result;
|
||||
|
||||
// Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55
|
||||
#if (CRYPTOPP_MSC_VERSION >= 1400)
|
||||
size_t len=0, size=0;
|
||||
errno_t err = 0;
|
||||
|
||||
//const wchar_t* ptr = str;
|
||||
//while (*ptr++) len++;
|
||||
len = wcslen(str)+1;
|
||||
|
||||
err = wcstombs_s(&size, NULLPTR, 0, str, len*sizeof(wchar_t));
|
||||
CRYPTOPP_ASSERT(err == 0);
|
||||
if (err != 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw InvalidArgument("StringNarrow: wcstombs_s() failed with error " + IntToString(err));
|
||||
else
|
||||
return std::string();
|
||||
}
|
||||
|
||||
result.resize(size);
|
||||
err = wcstombs_s(&size, &result[0], size, str, len*sizeof(wchar_t));
|
||||
CRYPTOPP_ASSERT(err == 0);
|
||||
if (err != 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw InvalidArgument("StringNarrow: wcstombs_s() failed with error " + IntToString(err));
|
||||
else
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// The safe routine's size includes the NULL.
|
||||
if (!result.empty() && result[size - 1] == '\0')
|
||||
result.erase(size - 1);
|
||||
#else
|
||||
size_t size = wcstombs(NULLPTR, str, 0);
|
||||
CRYPTOPP_ASSERT(size != (size_t)-1);
|
||||
if (size == (size_t)-1)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw InvalidArgument("StringNarrow: wcstombs() failed");
|
||||
else
|
||||
return std::string();
|
||||
}
|
||||
|
||||
result.resize(size);
|
||||
size = wcstombs(&result[0], str, size);
|
||||
CRYPTOPP_ASSERT(size != (size_t)-1);
|
||||
if (size == (size_t)-1)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw InvalidArgument("StringNarrow: wcstombs() failed");
|
||||
else
|
||||
return std::string();
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::wstring StringWiden(const char *str, bool throwOnError)
|
||||
{
|
||||
CRYPTOPP_ASSERT(str);
|
||||
std::wstring result;
|
||||
|
||||
// Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55
|
||||
#if (CRYPTOPP_MSC_VERSION >= 1400)
|
||||
size_t len=0, size=0;
|
||||
errno_t err = 0;
|
||||
|
||||
//const char* ptr = str;
|
||||
//while (*ptr++) len++;
|
||||
len = std::strlen(str)+1;
|
||||
|
||||
err = mbstowcs_s(&size, NULLPTR, 0, str, len);
|
||||
CRYPTOPP_ASSERT(err == 0);
|
||||
if (err != 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw InvalidArgument("StringWiden: wcstombs_s() failed with error " + IntToString(err));
|
||||
else
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
result.resize(size);
|
||||
err = mbstowcs_s(&size, &result[0], size, str, len);
|
||||
CRYPTOPP_ASSERT(err == 0);
|
||||
if (err != 0)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw InvalidArgument("StringWiden: wcstombs_s() failed with error " + IntToString(err));
|
||||
else
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
// The safe routine's size includes the NULL.
|
||||
if (!result.empty() && result[size - 1] == '\0')
|
||||
result.erase(size - 1);
|
||||
#else
|
||||
size_t size = mbstowcs(NULLPTR, str, 0);
|
||||
CRYPTOPP_ASSERT(size != (size_t)-1);
|
||||
if (size == (size_t)-1)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw InvalidArgument("StringWiden: mbstowcs() failed");
|
||||
else
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
result.resize(size);
|
||||
size = mbstowcs(&result[0], str, size);
|
||||
CRYPTOPP_ASSERT(size != (size_t)-1);
|
||||
if (size == (size_t)-1)
|
||||
{
|
||||
if (throwOnError)
|
||||
throw InvalidArgument("StringWiden: mbstowcs() failed");
|
||||
else
|
||||
return std::wstring();
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
2723
wasm_src/misc.h
Normal file
2723
wasm_src/misc.h
Normal file
File diff suppressed because it is too large
Load Diff
315
wasm_src/modarith.h
Normal file
315
wasm_src/modarith.h
Normal file
@ -0,0 +1,315 @@
|
||||
// modarith.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file modarith.h
|
||||
/// \brief Class file for performing modular arithmetic.
|
||||
|
||||
#ifndef CRYPTOPP_MODARITH_H
|
||||
#define CRYPTOPP_MODARITH_H
|
||||
|
||||
// implementations are in integer.cpp
|
||||
|
||||
#include "cryptlib.h"
|
||||
#include "integer.h"
|
||||
#include "algebra.h"
|
||||
#include "secblock.h"
|
||||
#include "misc.h"
|
||||
|
||||
#if CRYPTOPP_MSC_VERSION
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4231 4275)
|
||||
#endif
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
template class AbstractGroup<Integer>;
|
||||
template class AbstractRing<Integer>;
|
||||
template class AbstractEuclideanDomain<Integer>;
|
||||
|
||||
/// \brief Ring of congruence classes modulo n
|
||||
/// \details This implementation represents each congruence class as
|
||||
/// the smallest non-negative integer in that class.
|
||||
/// \details <tt>const Element&</tt> returned by member functions are
|
||||
/// references to internal data members. Since each object may have
|
||||
/// only one such data member for holding results, you should use the
|
||||
/// class like this:
|
||||
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
|
||||
/// The following code will produce <i>incorrect</i> results:
|
||||
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
|
||||
/// \details If a ModularArithmetic() is copied or assigned the modulus
|
||||
/// is copied, but not the internal data members. The internal data
|
||||
/// members are undefined after copy or assignment.
|
||||
/// \sa <A HREF="https://cryptopp.com/wiki/Integer">Integer</A> on the
|
||||
/// Crypto++ wiki.
|
||||
class CRYPTOPP_DLL ModularArithmetic : public AbstractRing<Integer>
|
||||
{
|
||||
public:
|
||||
|
||||
typedef int RandomizationParameter;
|
||||
typedef Integer Element;
|
||||
|
||||
virtual ~ModularArithmetic() {}
|
||||
|
||||
/// \brief Construct a ModularArithmetic
|
||||
/// \param modulus congruence class modulus
|
||||
ModularArithmetic(const Integer &modulus = Integer::One())
|
||||
: m_modulus(modulus), m_result(static_cast<word>(0), modulus.reg.size()) {}
|
||||
|
||||
/// \brief Copy construct a ModularArithmetic
|
||||
/// \param ma other ModularArithmetic
|
||||
ModularArithmetic(const ModularArithmetic &ma)
|
||||
: AbstractRing<Integer>(ma), m_modulus(ma.m_modulus), m_result(static_cast<word>(0), m_modulus.reg.size()) {}
|
||||
|
||||
/// \brief Assign a ModularArithmetic
|
||||
/// \param ma other ModularArithmetic
|
||||
ModularArithmetic& operator=(const ModularArithmetic &ma) {
|
||||
if (this != &ma)
|
||||
{
|
||||
m_modulus = ma.m_modulus;
|
||||
m_result = Integer(static_cast<word>(0), m_modulus.reg.size());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Clone a ModularArithmetic
|
||||
/// \return pointer to a new ModularArithmetic
|
||||
/// \details Clone effectively copy constructs a new ModularArithmetic. The caller is
|
||||
/// responsible for deleting the pointer returned from this method.
|
||||
virtual ModularArithmetic * Clone() const {return new ModularArithmetic(*this);}
|
||||
|
||||
/// \brief Retrieves the modulus
|
||||
/// \return the modulus
|
||||
const Integer& GetModulus() const {return m_modulus;}
|
||||
|
||||
/// \brief Sets the modulus
|
||||
/// \param newModulus the new modulus
|
||||
void SetModulus(const Integer &newModulus)
|
||||
{m_modulus = newModulus; m_result.reg.resize(m_modulus.reg.size());}
|
||||
|
||||
/// \brief Retrieves the representation
|
||||
/// \return true if the if the modulus is in Montgomery form for multiplication, false otherwise
|
||||
virtual bool IsMontgomeryRepresentation() const {return false;}
|
||||
|
||||
/// \brief Reduces an element in the congruence class
|
||||
/// \param a element to convert
|
||||
/// \return the reduced element
|
||||
/// \details ConvertIn is useful for derived classes, like MontgomeryRepresentation, which
|
||||
/// must convert between representations.
|
||||
virtual Integer ConvertIn(const Integer &a) const
|
||||
{return a%m_modulus;}
|
||||
|
||||
/// \brief Reduces an element in the congruence class
|
||||
/// \param a element to convert
|
||||
/// \return the reduced element
|
||||
/// \details ConvertOut is useful for derived classes, like MontgomeryRepresentation, which
|
||||
/// must convert between representations.
|
||||
virtual Integer ConvertOut(const Integer &a) const
|
||||
{return a;}
|
||||
|
||||
/// \brief Divides an element by 2
|
||||
/// \param a element to convert
|
||||
const Integer& Half(const Integer &a) const;
|
||||
|
||||
/// \brief Compare two elements for equality
|
||||
/// \param a first element
|
||||
/// \param b second element
|
||||
/// \return true if the elements are equal, false otherwise
|
||||
/// \details Equal() tests the elements for equality using <tt>a==b</tt>
|
||||
bool Equal(const Integer &a, const Integer &b) const
|
||||
{return a==b;}
|
||||
|
||||
/// \brief Provides the Identity element
|
||||
/// \return the Identity element
|
||||
const Integer& Identity() const
|
||||
{return Integer::Zero();}
|
||||
|
||||
/// \brief Adds elements in the ring
|
||||
/// \param a first element
|
||||
/// \param b second element
|
||||
/// \return the sum of <tt>a</tt> and <tt>b</tt>
|
||||
const Integer& Add(const Integer &a, const Integer &b) const;
|
||||
|
||||
/// \brief TODO
|
||||
/// \param a first element
|
||||
/// \param b second element
|
||||
/// \return TODO
|
||||
Integer& Accumulate(Integer &a, const Integer &b) const;
|
||||
|
||||
/// \brief Inverts the element in the ring
|
||||
/// \param a first element
|
||||
/// \return the inverse of the element
|
||||
const Integer& Inverse(const Integer &a) const;
|
||||
|
||||
/// \brief Subtracts elements in the ring
|
||||
/// \param a first element
|
||||
/// \param b second element
|
||||
/// \return the difference of <tt>a</tt> and <tt>b</tt>. The element <tt>a</tt> must provide a Subtract member function.
|
||||
const Integer& Subtract(const Integer &a, const Integer &b) const;
|
||||
|
||||
/// \brief TODO
|
||||
/// \param a first element
|
||||
/// \param b second element
|
||||
/// \return TODO
|
||||
Integer& Reduce(Integer &a, const Integer &b) const;
|
||||
|
||||
/// \brief Doubles an element in the ring
|
||||
/// \param a the element
|
||||
/// \return the element doubled
|
||||
/// \details Double returns <tt>Add(a, a)</tt>. The element <tt>a</tt> must provide an Add member function.
|
||||
const Integer& Double(const Integer &a) const
|
||||
{return Add(a, a);}
|
||||
|
||||
/// \brief Retrieves the multiplicative identity
|
||||
/// \return the multiplicative identity
|
||||
/// \details the base class implementations returns 1.
|
||||
const Integer& MultiplicativeIdentity() const
|
||||
{return Integer::One();}
|
||||
|
||||
/// \brief Multiplies elements in the ring
|
||||
/// \param a the multiplicand
|
||||
/// \param b the multiplier
|
||||
/// \return the product of a and b
|
||||
/// \details Multiply returns <tt>a*b\%n</tt>.
|
||||
const Integer& Multiply(const Integer &a, const Integer &b) const
|
||||
{return m_result1 = a*b%m_modulus;}
|
||||
|
||||
/// \brief Square an element in the ring
|
||||
/// \param a the element
|
||||
/// \return the element squared
|
||||
/// \details Square returns <tt>a*a\%n</tt>. The element <tt>a</tt> must provide a Square member function.
|
||||
const Integer& Square(const Integer &a) const
|
||||
{return m_result1 = a.Squared()%m_modulus;}
|
||||
|
||||
/// \brief Determines whether an element is a unit in the ring
|
||||
/// \param a the element
|
||||
/// \return true if the element is a unit after reduction, false otherwise.
|
||||
bool IsUnit(const Integer &a) const
|
||||
{return Integer::Gcd(a, m_modulus).IsUnit();}
|
||||
|
||||
/// \brief Calculate the multiplicative inverse of an element in the ring
|
||||
/// \param a the element
|
||||
/// \details MultiplicativeInverse returns <tt>a<sup>-1</sup>\%n</tt>. The element <tt>a</tt> must
|
||||
/// provide a InverseMod member function.
|
||||
const Integer& MultiplicativeInverse(const Integer &a) const
|
||||
{return m_result1 = a.InverseMod(m_modulus);}
|
||||
|
||||
/// \brief Divides elements in the ring
|
||||
/// \param a the dividend
|
||||
/// \param b the divisor
|
||||
/// \return the quotient
|
||||
/// \details Divide returns <tt>a*b<sup>-1</sup>\%n</tt>.
|
||||
const Integer& Divide(const Integer &a, const Integer &b) const
|
||||
{return Multiply(a, MultiplicativeInverse(b));}
|
||||
|
||||
/// \brief TODO
|
||||
/// \param x first element
|
||||
/// \param e1 first exponent
|
||||
/// \param y second element
|
||||
/// \param e2 second exponent
|
||||
/// \return TODO
|
||||
Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const;
|
||||
|
||||
/// \brief Exponentiates a base to multiple exponents in the ring
|
||||
/// \param results an array of Elements
|
||||
/// \param base the base to raise to the exponents
|
||||
/// \param exponents an array of exponents
|
||||
/// \param exponentsCount the number of exponents in the array
|
||||
/// \details SimultaneousExponentiate() raises the base to each exponent in the exponents array and stores the
|
||||
/// result at the respective position in the results array.
|
||||
/// \details SimultaneousExponentiate() must be implemented in a derived class.
|
||||
/// \pre <tt>COUNTOF(results) == exponentsCount</tt>
|
||||
/// \pre <tt>COUNTOF(exponents) == exponentsCount</tt>
|
||||
void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const;
|
||||
|
||||
/// \brief Provides the maximum bit size of an element in the ring
|
||||
/// \return maximum bit size of an element
|
||||
unsigned int MaxElementBitLength() const
|
||||
{return (m_modulus-1).BitCount();}
|
||||
|
||||
/// \brief Provides the maximum byte size of an element in the ring
|
||||
/// \return maximum byte size of an element
|
||||
unsigned int MaxElementByteLength() const
|
||||
{return (m_modulus-1).ByteCount();}
|
||||
|
||||
|
||||
|
||||
/// \brief Compares two ModularArithmetic for equality
|
||||
/// \param rhs other ModularArithmetic
|
||||
/// \return true if this is equal to the other, false otherwise
|
||||
/// \details The operator tests for equality using <tt>this.m_modulus == rhs.m_modulus</tt>.
|
||||
bool operator==(const ModularArithmetic &rhs) const
|
||||
{return m_modulus == rhs.m_modulus;}
|
||||
|
||||
static const RandomizationParameter DefaultRandomizationParameter;
|
||||
|
||||
private:
|
||||
// TODO: Clang on OS X needs a real operator=.
|
||||
// Squash warning on missing assignment operator.
|
||||
// ModularArithmetic& operator=(const ModularArithmetic &ma);
|
||||
|
||||
protected:
|
||||
Integer m_modulus;
|
||||
mutable Integer m_result, m_result1;
|
||||
};
|
||||
|
||||
// const ModularArithmetic::RandomizationParameter ModularArithmetic::DefaultRandomizationParameter = 0 ;
|
||||
|
||||
/// \brief Performs modular arithmetic in Montgomery representation for increased speed
|
||||
/// \details The Montgomery representation represents each congruence class <tt>[a]</tt> as
|
||||
/// <tt>a*r\%n</tt>, where <tt>r</tt> is a convenient power of 2.
|
||||
/// \details <tt>const Element&</tt> returned by member functions are references to
|
||||
/// internal data members. Since each object may have only one such data member for holding
|
||||
/// results, the following code will produce incorrect results:
|
||||
/// <pre> abcd = group.Add(group.Add(a,b), group.Add(c,d));</pre>
|
||||
/// But this should be fine:
|
||||
/// <pre> abcd = group.Add(a, group.Add(b, group.Add(c,d));</pre>
|
||||
class CRYPTOPP_DLL MontgomeryRepresentation : public ModularArithmetic
|
||||
{
|
||||
public:
|
||||
virtual ~MontgomeryRepresentation() {}
|
||||
|
||||
/// \brief Construct a MontgomeryRepresentation
|
||||
/// \param modulus congruence class modulus
|
||||
/// \note The modulus must be odd.
|
||||
MontgomeryRepresentation(const Integer &modulus);
|
||||
|
||||
/// \brief Clone a MontgomeryRepresentation
|
||||
/// \return pointer to a new MontgomeryRepresentation
|
||||
/// \details Clone effectively copy constructs a new MontgomeryRepresentation. The caller is
|
||||
/// responsible for deleting the pointer returned from this method.
|
||||
virtual ModularArithmetic * Clone() const {return new MontgomeryRepresentation(*this);}
|
||||
|
||||
bool IsMontgomeryRepresentation() const {return true;}
|
||||
|
||||
Integer ConvertIn(const Integer &a) const
|
||||
{return (a<<(WORD_BITS*m_modulus.reg.size()))%m_modulus;}
|
||||
|
||||
Integer ConvertOut(const Integer &a) const;
|
||||
|
||||
const Integer& MultiplicativeIdentity() const
|
||||
{return m_result1 = Integer::Power2(WORD_BITS*m_modulus.reg.size())%m_modulus;}
|
||||
|
||||
const Integer& Multiply(const Integer &a, const Integer &b) const;
|
||||
|
||||
const Integer& Square(const Integer &a) const;
|
||||
|
||||
const Integer& MultiplicativeInverse(const Integer &a) const;
|
||||
|
||||
Integer CascadeExponentiate(const Integer &x, const Integer &e1, const Integer &y, const Integer &e2) const
|
||||
{return AbstractRing<Integer>::CascadeExponentiate(x, e1, y, e2);}
|
||||
|
||||
void SimultaneousExponentiate(Element *results, const Element &base, const Integer *exponents, unsigned int exponentsCount) const
|
||||
{AbstractRing<Integer>::SimultaneousExponentiate(results, base, exponents, exponentsCount);}
|
||||
|
||||
private:
|
||||
Integer m_u;
|
||||
mutable IntegerSecBlock m_workspace;
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#if CRYPTOPP_MSC_VERSION
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
317
wasm_src/nbtheory.h
Normal file
317
wasm_src/nbtheory.h
Normal file
@ -0,0 +1,317 @@
|
||||
// nbtheory.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file nbtheory.h
|
||||
/// \brief Classes and functions for number theoretic operations
|
||||
|
||||
#ifndef CRYPTOPP_NBTHEORY_H
|
||||
#define CRYPTOPP_NBTHEORY_H
|
||||
|
||||
#include "cryptlib.h"
|
||||
#include "integer.h"
|
||||
#include "algparam.h"
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
/// \brief The Small Prime table
|
||||
/// \details GetPrimeTable obtains pointer to small prime table and provides the size of the table.
|
||||
CRYPTOPP_DLL const word16 * CRYPTOPP_API GetPrimeTable(unsigned int &size);
|
||||
|
||||
// ************ primality testing ****************
|
||||
|
||||
/// \brief Generates a provable prime
|
||||
/// \param rng a RandomNumberGenerator to produce random material
|
||||
/// \param bits the number of bits in the prime number
|
||||
/// \return Integer() meeting Maurer's tests for primality
|
||||
CRYPTOPP_DLL Integer CRYPTOPP_API MaurerProvablePrime(RandomNumberGenerator &rng, unsigned int bits);
|
||||
|
||||
/// \brief Generates a provable prime
|
||||
/// \param rng a RandomNumberGenerator to produce random material
|
||||
/// \param bits the number of bits in the prime number
|
||||
/// \return Integer() meeting Mihailescu's tests for primality
|
||||
/// \details Mihailescu's methods performs a search using algorithmic progressions.
|
||||
CRYPTOPP_DLL Integer CRYPTOPP_API MihailescuProvablePrime(RandomNumberGenerator &rng, unsigned int bits);
|
||||
|
||||
/// \brief Tests whether a number is a small prime
|
||||
/// \param p a candidate prime to test
|
||||
/// \return true if p is a small prime, false otherwise
|
||||
/// \details Internally, the library maintains a table of the first 32719 prime numbers
|
||||
/// in sorted order. IsSmallPrime searches the table and returns true if p is
|
||||
/// in the table.
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API IsSmallPrime(const Integer &p);
|
||||
|
||||
/// \brief Tests whether a number is divisible by a small prime
|
||||
/// \return true if p is divisible by some prime less than bound.
|
||||
/// \details TrialDivision() returns <tt>true</tt> if <tt>p</tt> is divisible by some prime less
|
||||
/// than <tt>bound</tt>. <tt>bound</tt> should not be greater than the largest entry in the
|
||||
/// prime table, which is 32719.
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API TrialDivision(const Integer &p, unsigned bound);
|
||||
|
||||
/// \brief Tests whether a number is divisible by a small prime
|
||||
/// \return true if p is NOT divisible by small primes.
|
||||
/// \details SmallDivisorsTest() returns <tt>true</tt> if <tt>p</tt> is NOT divisible by some
|
||||
/// prime less than 32719.
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API SmallDivisorsTest(const Integer &p);
|
||||
|
||||
/// \brief Determine if a number is probably prime
|
||||
/// \param n the number to test
|
||||
/// \param b the base to exponentiate
|
||||
/// \return true if the number n is probably prime, false otherwise.
|
||||
/// \details IsFermatProbablePrime raises <tt>b</tt> to the <tt>n-1</tt> power and checks if
|
||||
/// the result is congruent to 1 modulo <tt>n</tt>.
|
||||
/// \details These is no reason to use IsFermatProbablePrime, use IsStrongProbablePrime or
|
||||
/// IsStrongLucasProbablePrime instead.
|
||||
/// \sa IsStrongProbablePrime, IsStrongLucasProbablePrime
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API IsFermatProbablePrime(const Integer &n, const Integer &b);
|
||||
|
||||
/// \brief Determine if a number is probably prime
|
||||
/// \param n the number to test
|
||||
/// \return true if the number n is probably prime, false otherwise.
|
||||
/// \details These is no reason to use IsLucasProbablePrime, use IsStrongProbablePrime or
|
||||
/// IsStrongLucasProbablePrime instead.
|
||||
/// \sa IsStrongProbablePrime, IsStrongLucasProbablePrime
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API IsLucasProbablePrime(const Integer &n);
|
||||
|
||||
/// \brief Determine if a number is probably prime
|
||||
/// \param n the number to test
|
||||
/// \param b the base to exponentiate
|
||||
/// \return true if the number n is probably prime, false otherwise.
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API IsStrongProbablePrime(const Integer &n, const Integer &b);
|
||||
|
||||
/// \brief Determine if a number is probably prime
|
||||
/// \param n the number to test
|
||||
/// \return true if the number n is probably prime, false otherwise.
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API IsStrongLucasProbablePrime(const Integer &n);
|
||||
|
||||
/// \brief Determine if a number is probably prime
|
||||
/// \param rng a RandomNumberGenerator to produce random material
|
||||
/// \param n the number to test
|
||||
/// \param rounds the number of tests to perform
|
||||
/// \details This is the Rabin-Miller primality test, i.e. repeating the strong probable prime
|
||||
/// test for several rounds with random bases
|
||||
/// \sa <A HREF="https://crypto.stackexchange.com/q/17707/10496">Trial divisions before
|
||||
/// Miller-Rabin checks?</A> on Crypto Stack Exchange
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API RabinMillerTest(RandomNumberGenerator &rng, const Integer &n, unsigned int rounds);
|
||||
|
||||
/// \brief Verifies a number is probably prime
|
||||
/// \param p a candidate prime to test
|
||||
/// \return true if p is a probable prime, false otherwise
|
||||
/// \details IsPrime() is suitable for testing candidate primes when creating them. Internally,
|
||||
/// IsPrime() utilizes SmallDivisorsTest(), IsStrongProbablePrime() and IsStrongLucasProbablePrime().
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API IsPrime(const Integer &p);
|
||||
|
||||
/// \brief Verifies a number is probably prime
|
||||
/// \param rng a RandomNumberGenerator for randomized testing
|
||||
/// \param p a candidate prime to test
|
||||
/// \param level the level of thoroughness of testing
|
||||
/// \return true if p is a strong probable prime, false otherwise
|
||||
/// \details VerifyPrime() is suitable for testing candidate primes created by others. Internally,
|
||||
/// VerifyPrime() utilizes IsPrime() and one-round RabinMillerTest(). If the candidate passes and
|
||||
/// level is greater than 1, then 10 round RabinMillerTest() primality testing is performed.
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API VerifyPrime(RandomNumberGenerator &rng, const Integer &p, unsigned int level = 1);
|
||||
|
||||
/// \brief Application callback to signal suitability of a cabdidate prime
|
||||
class CRYPTOPP_DLL PrimeSelector
|
||||
{
|
||||
public:
|
||||
virtual ~PrimeSelector() {}
|
||||
const PrimeSelector *GetSelectorPointer() const {return this;}
|
||||
virtual bool IsAcceptable(const Integer &candidate) const =0;
|
||||
};
|
||||
|
||||
/// \brief Finds a random prime of special form
|
||||
/// \param p an Integer reference to receive the prime
|
||||
/// \param max the maximum value
|
||||
/// \param equiv the equivalence class based on the parameter mod
|
||||
/// \param mod the modulus used to reduce the equivalence class
|
||||
/// \param pSelector pointer to a PrimeSelector function for the application to signal suitability
|
||||
/// \return true if and only if FirstPrime() finds a prime and returns the prime through p. If FirstPrime()
|
||||
/// returns false, then no such prime exists and the value of p is undefined
|
||||
/// \details FirstPrime() uses a fast sieve to find the first probable prime
|
||||
/// in <tt>{x | p<=x<=max and x%mod==equiv}</tt>
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API FirstPrime(Integer &p, const Integer &max, const Integer &equiv, const Integer &mod, const PrimeSelector *pSelector);
|
||||
|
||||
CRYPTOPP_DLL unsigned int CRYPTOPP_API PrimeSearchInterval(const Integer &max);
|
||||
|
||||
CRYPTOPP_DLL AlgorithmParameters CRYPTOPP_API MakeParametersForTwoPrimesOfEqualSize(unsigned int productBitLength);
|
||||
|
||||
// ********** other number theoretic functions ************
|
||||
|
||||
/// \brief Calculate the greatest common divisor
|
||||
/// \param a the first term
|
||||
/// \param b the second term
|
||||
/// \return the greatest common divisor if one exists, 0 otherwise.
|
||||
inline Integer GCD(const Integer &a, const Integer &b)
|
||||
{return Integer::Gcd(a,b);}
|
||||
|
||||
/// \brief Determine relative primality
|
||||
/// \param a the first term
|
||||
/// \param b the second term
|
||||
/// \return true if <tt>a</tt> and <tt>b</tt> are relatively prime, false otherwise.
|
||||
inline bool RelativelyPrime(const Integer &a, const Integer &b)
|
||||
{return Integer::Gcd(a,b) == Integer::One();}
|
||||
|
||||
/// \brief Calculate the least common multiple
|
||||
/// \param a the first term
|
||||
/// \param b the second term
|
||||
/// \return the least common multiple of <tt>a</tt> and <tt>b</tt>.
|
||||
inline Integer LCM(const Integer &a, const Integer &b)
|
||||
{return a/Integer::Gcd(a,b)*b;}
|
||||
|
||||
/// \brief Calculate multiplicative inverse
|
||||
/// \param a the number to test
|
||||
/// \param b the modulus
|
||||
/// \return an Integer <tt>(a ^ -1) % n</tt> or 0 if none exists.
|
||||
/// \details EuclideanMultiplicativeInverse returns the multiplicative inverse of the Integer
|
||||
/// <tt>*a</tt> modulo the Integer <tt>b</tt>. If no Integer exists then Integer 0 is returned.
|
||||
inline Integer EuclideanMultiplicativeInverse(const Integer &a, const Integer &b)
|
||||
{return a.InverseMod(b);}
|
||||
|
||||
|
||||
/// \brief Chinese Remainder Theorem
|
||||
/// \param xp the first number, mod p
|
||||
/// \param p the first prime modulus
|
||||
/// \param xq the second number, mod q
|
||||
/// \param q the second prime modulus
|
||||
/// \param u inverse of p mod q
|
||||
/// \return the CRT value of the parameters
|
||||
/// \details CRT uses the Chinese Remainder Theorem to calculate <tt>x</tt> given
|
||||
/// <tt>x mod p</tt> and <tt>x mod q</tt>, and <tt>u</tt> the inverse of <tt>p mod q</tt>.
|
||||
CRYPTOPP_DLL Integer CRYPTOPP_API CRT(const Integer &xp, const Integer &p, const Integer &xq, const Integer &q, const Integer &u);
|
||||
|
||||
/// \brief Calculate the Jacobi symbol
|
||||
/// \param a the first term
|
||||
/// \param b the second term
|
||||
/// \return the Jacobi symbol.
|
||||
/// \details Jacobi symbols are calculated using the following rules:
|
||||
/// -# if <tt>b</tt> is prime, then <tt>Jacobi(a, b)</tt>, then return 0
|
||||
/// -# if <tt>a%b</tt>==0 AND <tt>a</tt> is quadratic residue <tt>mod b</tt>, then return 1
|
||||
/// -# return -1 otherwise
|
||||
/// \details Refer to a number theory book for what Jacobi symbol means when <tt>b</tt> is not prime.
|
||||
CRYPTOPP_DLL int CRYPTOPP_API Jacobi(const Integer &a, const Integer &b);
|
||||
|
||||
/// \brief Calculate the Lucas value
|
||||
/// \return the Lucas value
|
||||
/// \details Lucas() calculates the Lucas function <tt>V_e(p, 1) mod n</tt>.
|
||||
CRYPTOPP_DLL Integer CRYPTOPP_API Lucas(const Integer &e, const Integer &p, const Integer &n);
|
||||
|
||||
/// \brief Calculate the inverse Lucas value
|
||||
/// \return the inverse Lucas value
|
||||
/// \details InverseLucas() calculates <tt>x</tt> such that <tt>m==Lucas(e, x, p*q)</tt>,
|
||||
/// <tt>p q</tt> primes, <tt>u</tt> is inverse of <tt>p mod q</tt>.
|
||||
CRYPTOPP_DLL Integer CRYPTOPP_API InverseLucas(const Integer &e, const Integer &m, const Integer &p, const Integer &q, const Integer &u);
|
||||
|
||||
/// \brief Modular multiplication
|
||||
/// \param x the first term
|
||||
/// \param y the second term
|
||||
/// \param m the modulus
|
||||
/// \return an Integer <tt>(x * y) % m</tt>.
|
||||
inline Integer ModularMultiplication(const Integer &x, const Integer &y, const Integer &m)
|
||||
{return a_times_b_mod_c(x, y, m);}
|
||||
|
||||
/// \brief Modular exponentiation
|
||||
/// \param x the base
|
||||
/// \param e the exponent
|
||||
/// \param m the modulus
|
||||
/// \return an Integer <tt>(a ^ b) % m</tt>.
|
||||
inline Integer ModularExponentiation(const Integer &x, const Integer &e, const Integer &m)
|
||||
{return a_exp_b_mod_c(x, e, m);}
|
||||
|
||||
/// \brief Extract a modular square root
|
||||
/// \param a the number to extract square root
|
||||
/// \param p the prime modulus
|
||||
/// \return the modular square root if it exists
|
||||
/// \details ModularSquareRoot returns <tt>x</tt> such that <tt>x*x%p == a</tt>, <tt>p</tt> prime
|
||||
CRYPTOPP_DLL Integer CRYPTOPP_API ModularSquareRoot(const Integer &a, const Integer &p);
|
||||
|
||||
/// \brief Extract a modular root
|
||||
/// \return a modular root if it exists
|
||||
/// \details ModularRoot returns <tt>x</tt> such that <tt>a==ModularExponentiation(x, e, p*q)</tt>,
|
||||
/// <tt>p</tt> <tt>q</tt> primes, and <tt>e</tt> relatively prime to <tt>(p-1)*(q-1)</tt>,
|
||||
/// <tt>dp=d%(p-1)</tt>, <tt>dq=d%(q-1)</tt>, (d is inverse of <tt>e mod (p-1)*(q-1)</tt>)
|
||||
/// and <tt>u=inverse of p mod q</tt>.
|
||||
CRYPTOPP_DLL Integer CRYPTOPP_API ModularRoot(const Integer &a, const Integer &dp, const Integer &dq, const Integer &p, const Integer &q, const Integer &u);
|
||||
|
||||
/// \brief Solve a Modular Quadratic Equation
|
||||
/// \param r1 the first residue
|
||||
/// \param r2 the second residue
|
||||
/// \param a the first coefficient
|
||||
/// \param b the second coefficient
|
||||
/// \param c the third constant
|
||||
/// \param p the prime modulus
|
||||
/// \return true if solutions exist
|
||||
/// \details SolveModularQuadraticEquation() finds <tt>r1</tt> and <tt>r2</tt> such that <tt>ax^2 +
|
||||
/// bx + c == 0 (mod p)</tt> for x in <tt>{r1, r2}</tt>, <tt>p</tt> prime.
|
||||
CRYPTOPP_DLL bool CRYPTOPP_API SolveModularQuadraticEquation(Integer &r1, Integer &r2, const Integer &a, const Integer &b, const Integer &c, const Integer &p);
|
||||
|
||||
/// \brief Estimate work factor
|
||||
/// \param bitlength the size of the number, in bits
|
||||
/// \return the estimated work factor, in operations
|
||||
/// \details DiscreteLogWorkFactor returns log base 2 of estimated number of operations to
|
||||
/// calculate discrete log or factor a number.
|
||||
CRYPTOPP_DLL unsigned int CRYPTOPP_API DiscreteLogWorkFactor(unsigned int bitlength);
|
||||
|
||||
/// \brief Estimate work factor
|
||||
/// \param bitlength the size of the number, in bits
|
||||
/// \return the estimated work factor, in operations
|
||||
/// \details FactoringWorkFactor returns log base 2 of estimated number of operations to
|
||||
/// calculate discrete log or factor a number.
|
||||
CRYPTOPP_DLL unsigned int CRYPTOPP_API FactoringWorkFactor(unsigned int bitlength);
|
||||
|
||||
// ********************************************************
|
||||
|
||||
/// \brief Generator of prime numbers of special forms
|
||||
class CRYPTOPP_DLL PrimeAndGenerator
|
||||
{
|
||||
public:
|
||||
/// \brief Construct a PrimeAndGenerator
|
||||
PrimeAndGenerator() {}
|
||||
|
||||
/// \brief Construct a PrimeAndGenerator
|
||||
/// \param delta +1 or -1
|
||||
/// \param rng a RandomNumberGenerator derived class
|
||||
/// \param pbits the number of bits in the prime p
|
||||
/// \details PrimeAndGenerator() generates a random prime p of the form <tt>2*q+delta</tt>, where delta is 1 or -1 and q is
|
||||
/// also prime. Internally the constructor calls <tt>Generate(delta, rng, pbits, pbits-1)</tt>.
|
||||
/// \pre <tt>pbits > 5</tt>
|
||||
/// \warning This PrimeAndGenerator() is slow because primes of this form are harder to find.
|
||||
PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits)
|
||||
{Generate(delta, rng, pbits, pbits-1);}
|
||||
|
||||
/// \brief Construct a PrimeAndGenerator
|
||||
/// \param delta +1 or -1
|
||||
/// \param rng a RandomNumberGenerator derived class
|
||||
/// \param pbits the number of bits in the prime p
|
||||
/// \param qbits the number of bits in the prime q
|
||||
/// \details PrimeAndGenerator() generates a random prime p of the form <tt>2*r*q+delta</tt>, where q is also prime.
|
||||
/// Internally the constructor calls <tt>Generate(delta, rng, pbits, qbits)</tt>.
|
||||
/// \pre <tt>qbits > 4 && pbits > qbits</tt>
|
||||
PrimeAndGenerator(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits)
|
||||
{Generate(delta, rng, pbits, qbits);}
|
||||
|
||||
/// \brief Generate a Prime and Generator
|
||||
/// \param delta +1 or -1
|
||||
/// \param rng a RandomNumberGenerator derived class
|
||||
/// \param pbits the number of bits in the prime p
|
||||
/// \param qbits the number of bits in the prime q
|
||||
/// \details Generate() generates a random prime p of the form <tt>2*r*q+delta</tt>, where q is also prime.
|
||||
void Generate(signed int delta, RandomNumberGenerator &rng, unsigned int pbits, unsigned qbits);
|
||||
|
||||
/// \brief Retrieve first prime
|
||||
/// \return Prime() returns the prime p.
|
||||
const Integer& Prime() const {return p;}
|
||||
|
||||
/// \brief Retrieve second prime
|
||||
/// \return SubPrime() returns the prime q.
|
||||
const Integer& SubPrime() const {return q;}
|
||||
|
||||
/// \brief Retrieve the generator
|
||||
/// \return Generator() returns the generator g.
|
||||
const Integer& Generator() const {return g;}
|
||||
|
||||
private:
|
||||
Integer p, q, g;
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
31
wasm_src/pch.h
Normal file
31
wasm_src/pch.h
Normal file
@ -0,0 +1,31 @@
|
||||
// pch.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file pch.h
|
||||
/// \brief Precompiled header file
|
||||
/// \details The precompiled header files are used Windows.
|
||||
|
||||
#ifndef CRYPTOPP_PCH_H
|
||||
#define CRYPTOPP_PCH_H
|
||||
|
||||
# ifdef CRYPTOPP_GENERATE_X64_MASM
|
||||
#include "cpu.h"
|
||||
|
||||
# else
|
||||
#include "config.h"
|
||||
|
||||
#ifdef USE_PRECOMPILED_HEADERS
|
||||
#include "simple.h"
|
||||
#include "secblock.h"
|
||||
#include "misc.h"
|
||||
#include "smartptr.h"
|
||||
#include "stdcpp.h"
|
||||
#endif
|
||||
# endif
|
||||
|
||||
// Enable file and line numbers, if available.
|
||||
// #if defined(_MSC_VER) && defined(_DEBUG) && defined(USE_PRECOMPILED_HEADERS)
|
||||
// # define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
// # define new DEBUG_NEW
|
||||
// #endif
|
||||
|
||||
#endif // CRYPTOPP_PCH_H
|
272
wasm_src/queue.h
Normal file
272
wasm_src/queue.h
Normal file
@ -0,0 +1,272 @@
|
||||
// queue.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file
|
||||
/// \brief Classes for an unlimited queue to store bytes
|
||||
|
||||
#ifndef CRYPTOPP_QUEUE_H
|
||||
#define CRYPTOPP_QUEUE_H
|
||||
|
||||
#include "cryptlib.h"
|
||||
#include "simple.h"
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
class ByteQueueNode;
|
||||
|
||||
/// \brief Data structure used to store byte strings
|
||||
/// \details The queue is implemented as a linked list of byte arrays.
|
||||
/// Each byte array is stored in a ByteQueueNode.
|
||||
/// \sa <A HREF="https://www.cryptopp.com/wiki/ByteQueue">ByteQueue</A>
|
||||
/// on the Crypto++ wiki.
|
||||
/// \since Crypto++ 2.0
|
||||
class CRYPTOPP_DLL ByteQueue : public Bufferless<BufferedTransformation>
|
||||
{
|
||||
public:
|
||||
virtual ~ByteQueue();
|
||||
|
||||
/// \brief Construct a ByteQueue
|
||||
/// \param nodeSize the initial node size
|
||||
/// \details Internally, ByteQueue uses a ByteQueueNode to store bytes,
|
||||
/// and <tt>nodeSize</tt> determines the size of the ByteQueueNode. A value
|
||||
/// of 0 indicates the ByteQueueNode should be automatically sized,
|
||||
/// which means a value of 256 is used.
|
||||
ByteQueue(size_t nodeSize=0);
|
||||
|
||||
/// \brief Copy construct a ByteQueue
|
||||
/// \param copy the other ByteQueue
|
||||
ByteQueue(const ByteQueue ©);
|
||||
|
||||
// BufferedTransformation
|
||||
lword MaxRetrievable() const
|
||||
{return CurrentSize();}
|
||||
bool AnyRetrievable() const
|
||||
{return !IsEmpty();}
|
||||
|
||||
void IsolatedInitialize(const NameValuePairs ¶meters);
|
||||
byte * CreatePutSpace(size_t &size);
|
||||
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking);
|
||||
|
||||
size_t Get(byte &outByte);
|
||||
size_t Get(byte *outString, size_t getMax);
|
||||
|
||||
size_t Peek(byte &outByte) const;
|
||||
size_t Peek(byte *outString, size_t peekMax) const;
|
||||
|
||||
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
|
||||
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
|
||||
|
||||
/// \brief Set node size
|
||||
/// \param nodeSize the new node size, in bytes
|
||||
/// \details The default node size is 256.
|
||||
void SetNodeSize(size_t nodeSize);
|
||||
|
||||
/// \brief Determine data size
|
||||
/// \return the data size, in bytes
|
||||
lword CurrentSize() const;
|
||||
|
||||
/// \brief Determine data availability
|
||||
/// \return true if the ByteQueue has data, false otherwise
|
||||
bool IsEmpty() const;
|
||||
|
||||
/// \brief Empty the queue
|
||||
void Clear();
|
||||
|
||||
/// \brief Insert data in the queue
|
||||
/// \param inByte a byte to insert
|
||||
/// \details Unget() inserts a byte at the head of the queue
|
||||
void Unget(byte inByte);
|
||||
|
||||
/// \brief Insert data in the queue
|
||||
/// \param inString a byte array to insert
|
||||
/// \param length the size of the byte array
|
||||
/// \details Unget() inserts a byte array at the head of the queue
|
||||
void Unget(const byte *inString, size_t length);
|
||||
|
||||
/// \brief Peek data in the queue
|
||||
/// \param contiguousSize the size of the data
|
||||
/// \details Spy() peeks at data at the head of the queue. Spy() does
|
||||
/// not remove data from the queue.
|
||||
/// \details The data's size is returned in <tt>contiguousSize</tt>.
|
||||
/// Spy() returns the size of the first byte array in the list. The
|
||||
/// entire data may be larger since the queue is a linked list of
|
||||
/// byte arrays.
|
||||
const byte * Spy(size_t &contiguousSize) const;
|
||||
|
||||
/// \brief Insert data in the queue
|
||||
/// \param inString a byte array to insert
|
||||
/// \param size the length of the byte array
|
||||
/// \details LazyPut() inserts a byte array at the tail of the queue.
|
||||
/// The data may not be copied at this point. Rather, the pointer
|
||||
/// and size to external data are recorded.
|
||||
/// \details Another call to Put() or LazyPut() will force the data to
|
||||
/// be copied. When lazy puts are used, the data is copied when
|
||||
/// FinalizeLazyPut() is called.
|
||||
/// \sa LazyPutter
|
||||
void LazyPut(const byte *inString, size_t size);
|
||||
|
||||
/// \brief Insert data in the queue
|
||||
/// \param inString a byte array to insert
|
||||
/// \param size the length of the byte array
|
||||
/// \details LazyPut() inserts a byte array at the tail of the queue.
|
||||
/// The data may not be copied at this point. Rather, the pointer
|
||||
/// and size to external data are recorded.
|
||||
/// \details Another call to Put() or LazyPut() will force the data to
|
||||
/// be copied. When lazy puts are used, the data is copied when
|
||||
/// FinalizeLazyPut() is called.
|
||||
/// \sa LazyPutter
|
||||
void LazyPutModifiable(byte *inString, size_t size);
|
||||
|
||||
/// \brief Remove data from the queue
|
||||
/// \param size the length of the data
|
||||
/// \throw InvalidArgument if there is no lazy data in the queue or if
|
||||
/// size is larger than the lazy string
|
||||
/// \details UndoLazyPut() truncates data inserted using LazyPut() by
|
||||
/// modifying size.
|
||||
/// \sa LazyPutter
|
||||
void UndoLazyPut(size_t size);
|
||||
|
||||
/// \brief Insert data in the queue
|
||||
/// \details FinalizeLazyPut() copies external data inserted using
|
||||
/// LazyPut() or LazyPutModifiable() into the tail of the queue.
|
||||
/// \sa LazyPutter
|
||||
void FinalizeLazyPut();
|
||||
|
||||
/// \brief Assign contents from another ByteQueue
|
||||
/// \param rhs the other ByteQueue
|
||||
/// \return reference to this ByteQueue
|
||||
ByteQueue & operator=(const ByteQueue &rhs);
|
||||
|
||||
/// \brief Bitwise compare two ByteQueue
|
||||
/// \param rhs the other ByteQueue
|
||||
/// \return true if the size and bits are equal, false otherwise
|
||||
/// \details operator==() walks each ByteQueue comparing bytes in
|
||||
/// each queue. operator==() is not constant time.
|
||||
bool operator==(const ByteQueue &rhs) const;
|
||||
|
||||
/// \brief Bitwise compare two ByteQueue
|
||||
/// \param rhs the other ByteQueue
|
||||
/// \return true if the size and bits are not equal, false otherwise
|
||||
/// \details operator!=() is implemented in terms of operator==().
|
||||
/// operator==() is not constant time.
|
||||
bool operator!=(const ByteQueue &rhs) const {return !operator==(rhs);}
|
||||
|
||||
/// \brief Retrieve data from the queue
|
||||
/// \param index of byte to retrieve
|
||||
/// \return byte at the specified index
|
||||
/// \details operator[]() does not perform bounds checking.
|
||||
byte operator[](lword index) const;
|
||||
|
||||
/// \brief Swap contents with another ByteQueue
|
||||
/// \param rhs the other ByteQueue
|
||||
void swap(ByteQueue &rhs);
|
||||
|
||||
/// \brief A ByteQueue iterator
|
||||
class Walker : public InputRejecting<BufferedTransformation>
|
||||
{
|
||||
public:
|
||||
/// \brief Construct a ByteQueue Walker
|
||||
/// \param queue a ByteQueue
|
||||
Walker(const ByteQueue &queue)
|
||||
: m_queue(queue), m_node(NULLPTR), m_position(0), m_offset(0), m_lazyString(NULLPTR), m_lazyLength(0)
|
||||
{Initialize();}
|
||||
|
||||
lword GetCurrentPosition() {return m_position;}
|
||||
|
||||
lword MaxRetrievable() const
|
||||
{return m_queue.CurrentSize() - m_position;}
|
||||
|
||||
void IsolatedInitialize(const NameValuePairs ¶meters);
|
||||
|
||||
size_t Get(byte &outByte);
|
||||
size_t Get(byte *outString, size_t getMax);
|
||||
|
||||
size_t Peek(byte &outByte) const;
|
||||
size_t Peek(byte *outString, size_t peekMax) const;
|
||||
|
||||
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true);
|
||||
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const;
|
||||
|
||||
private:
|
||||
const ByteQueue &m_queue;
|
||||
const ByteQueueNode *m_node;
|
||||
lword m_position;
|
||||
size_t m_offset;
|
||||
const byte *m_lazyString;
|
||||
size_t m_lazyLength;
|
||||
};
|
||||
|
||||
friend class Walker;
|
||||
|
||||
protected:
|
||||
void CleanupUsedNodes();
|
||||
void CopyFrom(const ByteQueue ©);
|
||||
void Destroy();
|
||||
|
||||
private:
|
||||
ByteQueueNode *m_head, *m_tail;
|
||||
byte *m_lazyString;
|
||||
size_t m_lazyLength;
|
||||
size_t m_nodeSize;
|
||||
bool m_lazyStringModifiable;
|
||||
bool m_autoNodeSize;
|
||||
};
|
||||
|
||||
/// \brief Helper class to finalize Puts on ByteQueue
|
||||
/// \details LazyPutter ensures LazyPut is committed to the ByteQueue
|
||||
/// in event of exception. During destruction, the LazyPutter class
|
||||
/// calls FinalizeLazyPut.
|
||||
class CRYPTOPP_DLL LazyPutter
|
||||
{
|
||||
public:
|
||||
virtual ~LazyPutter() {
|
||||
try {m_bq.FinalizeLazyPut();}
|
||||
catch(const Exception&) {CRYPTOPP_ASSERT(0);}
|
||||
}
|
||||
|
||||
/// \brief Construct a LazyPutter
|
||||
/// \param bq the ByteQueue
|
||||
/// \param inString a byte array to insert
|
||||
/// \param size the length of the byte array
|
||||
/// \details LazyPutter ensures LazyPut is committed to the ByteQueue
|
||||
/// in event of exception. During destruction, the LazyPutter class
|
||||
/// calls FinalizeLazyPut.
|
||||
LazyPutter(ByteQueue &bq, const byte *inString, size_t size)
|
||||
: m_bq(bq) {bq.LazyPut(inString, size);}
|
||||
|
||||
protected:
|
||||
LazyPutter(ByteQueue &bq) : m_bq(bq) {}
|
||||
|
||||
private:
|
||||
ByteQueue &m_bq;
|
||||
};
|
||||
|
||||
/// \brief Helper class to finalize Puts on ByteQueue
|
||||
/// \details LazyPutterModifiable ensures LazyPut is committed to the
|
||||
/// ByteQueue in event of exception. During destruction, the
|
||||
/// LazyPutterModifiable class calls FinalizeLazyPut.
|
||||
class LazyPutterModifiable : public LazyPutter
|
||||
{
|
||||
public:
|
||||
/// \brief Construct a LazyPutterModifiable
|
||||
/// \param bq the ByteQueue
|
||||
/// \param inString a byte array to insert
|
||||
/// \param size the length of the byte array
|
||||
/// \details LazyPutterModifiable ensures LazyPut is committed to the
|
||||
/// ByteQueue in event of exception. During destruction, the
|
||||
/// LazyPutterModifiable class calls FinalizeLazyPut.
|
||||
LazyPutterModifiable(ByteQueue &bq, byte *inString, size_t size)
|
||||
: LazyPutter(bq) {bq.LazyPutModifiable(inString, size);}
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#ifndef __BORLANDC__
|
||||
NAMESPACE_BEGIN(std)
|
||||
template<> inline void swap(CryptoPP::ByteQueue &a, CryptoPP::ByteQueue &b)
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
NAMESPACE_END
|
||||
#endif
|
||||
|
||||
#endif
|
1299
wasm_src/secblock.h
Normal file
1299
wasm_src/secblock.h
Normal file
File diff suppressed because it is too large
Load Diff
29
wasm_src/secblockfwd.h
Normal file
29
wasm_src/secblockfwd.h
Normal file
@ -0,0 +1,29 @@
|
||||
// secblockfwd.h - written and placed in the public domain by Jeffrey Walton
|
||||
|
||||
/// \file secblockfwd.h
|
||||
/// \brief Forward declarations for SecBlock
|
||||
/// \details secblock.h and misc.h have a circular dependency. secblockfwd.h
|
||||
/// allows the library to sidestep the circular dependency, and reference
|
||||
/// SecBlock classes without the full implementation.
|
||||
/// \since Crypto++ 8.3
|
||||
|
||||
#ifndef CRYPTOPP_SECBLOCKFWD_H
|
||||
#define CRYPTOPP_SECBLOCKFWD_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
template <class T, class A>
|
||||
class SecBlock;
|
||||
|
||||
template <class T, bool A>
|
||||
class AllocatorWithCleanup;
|
||||
|
||||
typedef SecBlock<byte, AllocatorWithCleanup<byte, false> > SecByteBlock;
|
||||
typedef SecBlock<word, AllocatorWithCleanup<word, false> > SecWordBlock;
|
||||
typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif // CRYPTOPP_SECBLOCKFWD_H
|
506
wasm_src/simple.h
Normal file
506
wasm_src/simple.h
Normal file
@ -0,0 +1,506 @@
|
||||
// simple.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file simple.h
|
||||
/// \brief Classes providing basic library services.
|
||||
|
||||
#ifndef CRYPTOPP_SIMPLE_H
|
||||
#define CRYPTOPP_SIMPLE_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if CRYPTOPP_MSC_VERSION
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4127 4189)
|
||||
#endif
|
||||
|
||||
#include "cryptlib.h"
|
||||
#include "misc.h"
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
/// \brief Base class for identifying alogorithm
|
||||
/// \tparam BASE base class from which to derive
|
||||
/// \tparam DERIVED class which to clone
|
||||
template <class DERIVED, class BASE>
|
||||
class CRYPTOPP_NO_VTABLE ClonableImpl : public BASE
|
||||
{
|
||||
public:
|
||||
/// \brief Create a copy of this object
|
||||
/// \return a copy of this object
|
||||
/// \details The caller is responsible for freeing the object.
|
||||
Clonable * Clone() const {return new DERIVED(*static_cast<const DERIVED *>(this));}
|
||||
};
|
||||
|
||||
/// \brief Base class information
|
||||
/// \tparam BASE an Algorithm derived class
|
||||
/// \tparam ALGORITHM_INFO an Algorithm derived class
|
||||
/// \details AlgorithmImpl provides StaticAlgorithmName from the template parameter BASE
|
||||
template <class BASE, class ALGORITHM_INFO=BASE>
|
||||
class CRYPTOPP_NO_VTABLE AlgorithmImpl : public BASE
|
||||
{
|
||||
public:
|
||||
/// \brief The algorithm name
|
||||
/// \return the algorithm name
|
||||
/// \details StaticAlgorithmName returns the algorithm's name as a static member function.
|
||||
/// The name is taken from information provided by BASE.
|
||||
static std::string CRYPTOPP_API StaticAlgorithmName() {return ALGORITHM_INFO::StaticAlgorithmName();}
|
||||
/// \brief The algorithm name
|
||||
/// \return the algorithm name
|
||||
/// \details AlgorithmName returns the algorithm's name as a member function.
|
||||
/// The name is acquired by calling StaticAlgorithmName.
|
||||
std::string AlgorithmName() const {return ALGORITHM_INFO::StaticAlgorithmName();}
|
||||
};
|
||||
|
||||
/// \brief Exception thrown when an invalid key length is encountered
|
||||
class CRYPTOPP_DLL InvalidKeyLength : public InvalidArgument
|
||||
{
|
||||
public:
|
||||
/// \brief Construct an InvalidKeyLength
|
||||
/// \param algorithm the Algorithm associated with the exception
|
||||
/// \param length the key size associated with the exception
|
||||
explicit InvalidKeyLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid key length") {}
|
||||
};
|
||||
|
||||
/// \brief Exception thrown when an invalid number of rounds is encountered
|
||||
class CRYPTOPP_DLL InvalidRounds : public InvalidArgument
|
||||
{
|
||||
public:
|
||||
/// \brief Construct an InvalidRounds
|
||||
/// \param algorithm the Algorithm associated with the exception
|
||||
/// \param rounds the number of rounds associated with the exception
|
||||
explicit InvalidRounds(const std::string &algorithm, unsigned int rounds) : InvalidArgument(algorithm + ": " + IntToString(rounds) + " is not a valid number of rounds") {}
|
||||
};
|
||||
|
||||
/// \brief Exception thrown when an invalid block size is encountered
|
||||
class CRYPTOPP_DLL InvalidBlockSize : public InvalidArgument
|
||||
{
|
||||
public:
|
||||
/// \brief Construct an InvalidBlockSize
|
||||
/// \param algorithm the Algorithm associated with the exception
|
||||
/// \param length the block size associated with the exception
|
||||
explicit InvalidBlockSize(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid block size") {}
|
||||
};
|
||||
|
||||
/// \brief Exception thrown when an invalid derived key length is encountered
|
||||
class CRYPTOPP_DLL InvalidDerivedKeyLength : public InvalidArgument
|
||||
{
|
||||
public:
|
||||
/// \brief Construct an InvalidDerivedKeyLength
|
||||
/// \param algorithm the Algorithm associated with the exception
|
||||
/// \param length the size associated with the exception
|
||||
explicit InvalidDerivedKeyLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid derived key length") {}
|
||||
};
|
||||
|
||||
/// \brief Exception thrown when an invalid personalization string length is encountered
|
||||
class CRYPTOPP_DLL InvalidPersonalizationLength : public InvalidArgument
|
||||
{
|
||||
public:
|
||||
/// \brief Construct an InvalidPersonalizationLength
|
||||
/// \param algorithm the Algorithm associated with the exception
|
||||
/// \param length the personalization size associated with the exception
|
||||
explicit InvalidPersonalizationLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid salt length") {}
|
||||
};
|
||||
|
||||
/// \brief Exception thrown when an invalid salt length is encountered
|
||||
class CRYPTOPP_DLL InvalidSaltLength : public InvalidArgument
|
||||
{
|
||||
public:
|
||||
/// \brief Construct an InvalidSaltLength
|
||||
/// \param algorithm the Algorithm associated with the exception
|
||||
/// \param length the salt size associated with the exception
|
||||
explicit InvalidSaltLength(const std::string &algorithm, size_t length) : InvalidArgument(algorithm + ": " + IntToString(length) + " is not a valid salt length") {}
|
||||
};
|
||||
|
||||
// *****************************
|
||||
|
||||
/// \brief Base class for bufferless filters
|
||||
/// \tparam T the class or type
|
||||
template <class T>
|
||||
class CRYPTOPP_NO_VTABLE Bufferless : public T
|
||||
{
|
||||
public:
|
||||
/// \brief Flushes data buffered by this object, without signal propagation
|
||||
/// \param hardFlush indicates whether all data should be flushed
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \note hardFlush must be used with care
|
||||
bool IsolatedFlush(bool hardFlush, bool blocking)
|
||||
{CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); return false;}
|
||||
};
|
||||
|
||||
/// \brief Base class for unflushable filters
|
||||
/// \tparam T the class or type
|
||||
template <class T>
|
||||
class CRYPTOPP_NO_VTABLE Unflushable : public T
|
||||
{
|
||||
public:
|
||||
/// \brief Flush buffered input and/or output, with signal propagation
|
||||
/// \param completeFlush is used to indicate whether all data should be flushed
|
||||
/// \param propagation the number of attached transformations the Flush()
|
||||
/// signal should be passed
|
||||
/// \param blocking specifies whether the object should block when processing
|
||||
/// input
|
||||
/// \details propagation count includes this object. Setting propagation to
|
||||
/// <tt>1</tt> means this object only. Setting propagation to <tt>-1</tt>
|
||||
/// means unlimited propagation.
|
||||
/// \note Hard flushes must be used with care. It means try to process and
|
||||
/// output everything, even if there may not be enough data to complete the
|
||||
/// action. For example, hard flushing a HexDecoder would cause an error if
|
||||
/// you do it after inputing an odd number of hex encoded characters.
|
||||
/// \note For some types of filters, like ZlibDecompressor, hard flushes can
|
||||
/// only be done at "synchronization points". These synchronization points
|
||||
/// are positions in the data stream that are created by hard flushes on the
|
||||
/// corresponding reverse filters, in this example ZlibCompressor. This is
|
||||
/// useful when zlib compressed data is moved across a network in packets
|
||||
/// and compression state is preserved across packets, as in the SSH2 protocol.
|
||||
bool Flush(bool completeFlush, int propagation=-1, bool blocking=true)
|
||||
{return ChannelFlush(DEFAULT_CHANNEL, completeFlush, propagation, blocking);}
|
||||
|
||||
/// \brief Flushes data buffered by this object, without signal propagation
|
||||
/// \param hardFlush indicates whether all data should be flushed
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \note hardFlush must be used with care
|
||||
bool IsolatedFlush(bool hardFlush, bool blocking)
|
||||
{CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); CRYPTOPP_ASSERT(false); return false;}
|
||||
|
||||
/// \brief Flush buffered input and/or output on a channel
|
||||
/// \param channel the channel to flush the data
|
||||
/// \param hardFlush is used to indicate whether all data should be flushed
|
||||
/// \param propagation the number of attached transformations the ChannelFlush()
|
||||
/// signal should be passed
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \return true of the Flush was successful
|
||||
/// \details propagation count includes this object. Setting propagation to
|
||||
/// <tt>1</tt> means this object only. Setting propagation to <tt>-1</tt> means
|
||||
/// unlimited propagation.
|
||||
bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true)
|
||||
{
|
||||
if (hardFlush && !InputBufferIsEmpty())
|
||||
throw CannotFlush("Unflushable<T>: this object has buffered input that cannot be flushed");
|
||||
else
|
||||
{
|
||||
BufferedTransformation *attached = this->AttachedTransformation();
|
||||
return attached && propagation ? attached->ChannelFlush(channel, hardFlush, propagation-1, blocking) : false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool InputBufferIsEmpty() const {return false;}
|
||||
};
|
||||
|
||||
/// \brief Base class for input rejecting filters
|
||||
/// \tparam T the class or type
|
||||
/// \details T should be a BufferedTransformation derived class
|
||||
template <class T>
|
||||
class CRYPTOPP_NO_VTABLE InputRejecting : public T
|
||||
{
|
||||
public:
|
||||
struct InputRejected : public NotImplemented
|
||||
{InputRejected() : NotImplemented("BufferedTransformation: this object doesn't allow input") {}};
|
||||
|
||||
/// \name INPUT
|
||||
//@{
|
||||
|
||||
/// \brief Input a byte array for processing
|
||||
/// \param inString the byte array to process
|
||||
/// \param length the size of the string, in bytes
|
||||
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \throw InputRejected
|
||||
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
|
||||
/// \details Internally, the default implementation throws InputRejected.
|
||||
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
|
||||
{CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();}
|
||||
//@}
|
||||
|
||||
/// \name SIGNALS
|
||||
//@{
|
||||
|
||||
/// \brief Flushes data buffered by this object, without signal propagation
|
||||
/// \param hardFlush indicates whether all data should be flushed
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \note hardFlush must be used with care
|
||||
bool IsolatedFlush(bool hardFlush, bool blocking)
|
||||
{CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); return false;}
|
||||
|
||||
/// \brief Marks the end of a series of messages, without signal propagation
|
||||
/// \param blocking specifies whether the object should block when completing the processing on
|
||||
/// the current series of messages
|
||||
/// \return true if the message was successful, false otherwise
|
||||
bool IsolatedMessageSeriesEnd(bool blocking)
|
||||
{CRYPTOPP_UNUSED(blocking); throw InputRejected();}
|
||||
|
||||
/// \brief Input multiple bytes for processing on a channel.
|
||||
/// \param channel the channel to process the data.
|
||||
/// \param inString the byte buffer to process.
|
||||
/// \param length the size of the string, in bytes.
|
||||
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one.
|
||||
/// \param blocking specifies whether the object should block when processing input.
|
||||
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
|
||||
size_t ChannelPut2(const std::string &channel, const byte *inString, size_t length, int messageEnd, bool blocking)
|
||||
{CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length);
|
||||
CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();}
|
||||
|
||||
/// \brief Marks the end of a series of messages on a channel
|
||||
/// \param channel the channel to signal the end of a series of messages
|
||||
/// \param messageEnd the number of attached transformations the ChannelMessageSeriesEnd() signal should be passed
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \return true if the message was successful, false otherwise
|
||||
/// \details Each object that receives the signal will perform its processing, decrement
|
||||
/// propagation, and then pass the signal on to attached transformations if the value is not 0.
|
||||
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
|
||||
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
|
||||
/// \note There should be a MessageEnd() immediately before MessageSeriesEnd().
|
||||
bool ChannelMessageSeriesEnd(const std::string& channel, int messageEnd, bool blocking)
|
||||
{CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); throw InputRejected();}
|
||||
//@}
|
||||
};
|
||||
|
||||
/// \brief Interface for custom flush signals propagation
|
||||
/// \tparam T BufferedTransformation derived class
|
||||
template <class T>
|
||||
class CRYPTOPP_NO_VTABLE CustomFlushPropagation : public T
|
||||
{
|
||||
public:
|
||||
/// \name SIGNALS
|
||||
//@{
|
||||
|
||||
/// \brief Flush buffered input and/or output, with signal propagation
|
||||
/// \param hardFlush is used to indicate whether all data should be flushed
|
||||
/// \param propagation the number of attached transformations the Flush() signal should be passed
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
|
||||
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
|
||||
/// \note Hard flushes must be used with care. It means try to process and output everything, even if
|
||||
/// there may not be enough data to complete the action. For example, hard flushing a HexDecoder
|
||||
/// would cause an error if you do it after inputing an odd number of hex encoded characters.
|
||||
/// \note For some types of filters, like ZlibDecompressor, hard flushes can only
|
||||
/// be done at "synchronization points". These synchronization points are positions in the data
|
||||
/// stream that are created by hard flushes on the corresponding reverse filters, in this
|
||||
/// example ZlibCompressor. This is useful when zlib compressed data is moved across a
|
||||
/// network in packets and compression state is preserved across packets, as in the SSH2 protocol.
|
||||
virtual bool Flush(bool hardFlush, int propagation=-1, bool blocking=true) =0;
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
bool IsolatedFlush(bool hardFlush, bool blocking)
|
||||
{CRYPTOPP_UNUSED(hardFlush); CRYPTOPP_UNUSED(blocking); CRYPTOPP_ASSERT(false); return false;}
|
||||
};
|
||||
|
||||
/// \brief Interface for custom flush signals
|
||||
/// \tparam T BufferedTransformation derived class
|
||||
template <class T>
|
||||
class CRYPTOPP_NO_VTABLE CustomSignalPropagation : public CustomFlushPropagation<T>
|
||||
{
|
||||
public:
|
||||
/// \brief Initialize or reinitialize this object, with signal propagation
|
||||
/// \param parameters a set of NameValuePairs to initialize or reinitialize this object
|
||||
/// \param propagation the number of attached transformations the Initialize() signal should be passed
|
||||
/// \details Initialize() is used to initialize or reinitialize an object using a variable number of
|
||||
/// arbitrarily typed arguments. The function avoids the need for multiple constructors providing
|
||||
/// all possible combintations of configurable parameters.
|
||||
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
|
||||
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
|
||||
virtual void Initialize(const NameValuePairs ¶meters=g_nullNameValuePairs, int propagation=-1) =0;
|
||||
|
||||
private:
|
||||
void IsolatedInitialize(const NameValuePairs ¶meters)
|
||||
{CRYPTOPP_UNUSED(parameters); CRYPTOPP_ASSERT(false);}
|
||||
};
|
||||
|
||||
/// \brief Multiple channels support for custom signal processing
|
||||
/// \tparam T the class or type
|
||||
/// \details T should be a BufferedTransformation derived class
|
||||
template <class T>
|
||||
class CRYPTOPP_NO_VTABLE Multichannel : public CustomFlushPropagation<T>
|
||||
{
|
||||
public:
|
||||
bool Flush(bool hardFlush, int propagation=-1, bool blocking=true)
|
||||
{return this->ChannelFlush(DEFAULT_CHANNEL, hardFlush, propagation, blocking);}
|
||||
|
||||
/// \brief Marks the end of a series of messages, with signal propagation
|
||||
/// \param propagation the number of attached transformations the MessageSeriesEnd() signal should be passed
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \details Each object that receives the signal will perform its processing, decrement
|
||||
/// propagation, and then pass the signal on to attached transformations if the value is not 0.
|
||||
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
|
||||
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
|
||||
/// \note There should be a MessageEnd() immediately before MessageSeriesEnd().
|
||||
bool MessageSeriesEnd(int propagation=-1, bool blocking=true)
|
||||
{return this->ChannelMessageSeriesEnd(DEFAULT_CHANNEL, propagation, blocking);}
|
||||
|
||||
/// \brief Request space which can be written into by the caller
|
||||
/// \param size the requested size of the buffer
|
||||
/// \details The purpose of this method is to help avoid extra memory allocations.
|
||||
/// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made,
|
||||
/// size is the requested size of the buffer. When the call returns, size is the size of
|
||||
/// the array returned to the caller.
|
||||
/// \details The base class implementation sets size to 0 and returns NULL.
|
||||
/// \note Some objects, like ArraySink, cannot create a space because its fixed. In the case of
|
||||
/// an ArraySink, the pointer to the array is returned and the size is remaining size.
|
||||
byte * CreatePutSpace(size_t &size)
|
||||
{return this->ChannelCreatePutSpace(DEFAULT_CHANNEL, size);}
|
||||
|
||||
/// \brief Input multiple bytes for processing
|
||||
/// \param inString the byte buffer to process
|
||||
/// \param length the size of the string, in bytes
|
||||
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
|
||||
/// \details Derived classes must implement Put2().
|
||||
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
|
||||
{return this->ChannelPut2(DEFAULT_CHANNEL, inString, length, messageEnd, blocking);}
|
||||
|
||||
/// \brief Input multiple bytes that may be modified by callee.
|
||||
/// \param inString the byte buffer to process.
|
||||
/// \param length the size of the string, in bytes.
|
||||
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one.
|
||||
/// \param blocking specifies whether the object should block when processing input.
|
||||
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
|
||||
/// \details Internally, PutModifiable2() calls Put2().
|
||||
size_t PutModifiable2(byte *inString, size_t length, int messageEnd, bool blocking)
|
||||
{return this->ChannelPutModifiable2(DEFAULT_CHANNEL, inString, length, messageEnd, blocking);}
|
||||
|
||||
// void ChannelMessageSeriesEnd(const std::string &channel, int propagation=-1)
|
||||
// {PropagateMessageSeriesEnd(propagation, channel);}
|
||||
|
||||
/// \brief Request space which can be written into by the caller
|
||||
/// \param channel the channel to process the data
|
||||
/// \param size the requested size of the buffer
|
||||
/// \return a pointer to a memory block with length size
|
||||
/// \details The purpose of this method is to help avoid extra memory allocations.
|
||||
/// \details size is an \a IN and \a OUT parameter and used as a hint. When the call is made,
|
||||
/// size is the requested size of the buffer. When the call returns, size is the size of
|
||||
/// the array returned to the caller.
|
||||
/// \details The base class implementation sets size to 0 and returns NULL.
|
||||
/// \note Some objects, like ArraySink(), cannot create a space because its fixed. In the case of
|
||||
/// an ArraySink(), the pointer to the array is returned and the size is remaining size.
|
||||
byte * ChannelCreatePutSpace(const std::string &channel, size_t &size)
|
||||
{CRYPTOPP_UNUSED(channel); size = 0; return NULLPTR;}
|
||||
|
||||
/// \brief Input multiple bytes that may be modified by callee on a channel
|
||||
/// \param channel the channel to process the data.
|
||||
/// \param inString the byte buffer to process
|
||||
/// \param length the size of the string, in bytes
|
||||
/// \return true if all bytes were processed, false otherwise.
|
||||
bool ChannelPutModifiable(const std::string &channel, byte *inString, size_t length)
|
||||
{this->ChannelPut(channel, inString, length); return false;}
|
||||
|
||||
/// \brief Input multiple bytes for processing on a channel.
|
||||
/// \param channel the channel to process the data.
|
||||
/// \param begin the byte buffer to process.
|
||||
/// \param length the size of the string, in bytes.
|
||||
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one.
|
||||
/// \param blocking specifies whether the object should block when processing input.
|
||||
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
|
||||
virtual size_t ChannelPut2(const std::string &channel, const byte *begin, size_t length, int messageEnd, bool blocking) =0;
|
||||
|
||||
/// \brief Input multiple bytes that may be modified by callee on a channel
|
||||
/// \param channel the channel to process the data
|
||||
/// \param begin the byte buffer to process
|
||||
/// \param length the size of the string, in bytes
|
||||
/// \param messageEnd means how many filters to signal MessageEnd() to, including this one
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \return the number of bytes that remain to be processed (i.e., bytes not processed)
|
||||
size_t ChannelPutModifiable2(const std::string &channel, byte *begin, size_t length, int messageEnd, bool blocking)
|
||||
{return ChannelPut2(channel, begin, length, messageEnd, blocking);}
|
||||
|
||||
/// \brief Flush buffered input and/or output on a channel
|
||||
/// \param channel the channel to flush the data
|
||||
/// \param hardFlush is used to indicate whether all data should be flushed
|
||||
/// \param propagation the number of attached transformations the ChannelFlush() signal should be passed
|
||||
/// \param blocking specifies whether the object should block when processing input
|
||||
/// \return true of the Flush was successful
|
||||
/// \details propagation count includes this object. Setting propagation to <tt>1</tt> means this
|
||||
/// object only. Setting propagation to <tt>-1</tt> means unlimited propagation.
|
||||
virtual bool ChannelFlush(const std::string &channel, bool hardFlush, int propagation=-1, bool blocking=true) =0;
|
||||
};
|
||||
|
||||
/// \brief Provides auto signaling support
|
||||
/// \tparam T BufferedTransformation derived class
|
||||
template <class T>
|
||||
class CRYPTOPP_NO_VTABLE AutoSignaling : public T
|
||||
{
|
||||
public:
|
||||
/// \brief Construct an AutoSignaling
|
||||
/// \param propagation the propagation count
|
||||
AutoSignaling(int propagation=-1) : m_autoSignalPropagation(propagation) {}
|
||||
|
||||
/// \brief Set propagation of automatically generated and transferred signals
|
||||
/// \param propagation then new value
|
||||
/// \details Setting propagation to <tt>0</tt> means do not automatically generate signals. Setting
|
||||
/// propagation to <tt>-1</tt> means unlimited propagation.
|
||||
void SetAutoSignalPropagation(int propagation)
|
||||
{m_autoSignalPropagation = propagation;}
|
||||
|
||||
/// \brief Retrieve automatic signal propagation value
|
||||
/// \return the number of attached transformations the signal is propagated to. 0 indicates
|
||||
/// the signal is only witnessed by this object
|
||||
int GetAutoSignalPropagation() const
|
||||
{return m_autoSignalPropagation;}
|
||||
|
||||
private:
|
||||
int m_autoSignalPropagation;
|
||||
};
|
||||
|
||||
/// \brief Acts as a Source for pre-existing, static data
|
||||
class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Store : public AutoSignaling<InputRejecting<BufferedTransformation> >
|
||||
{
|
||||
public:
|
||||
/// \brief Construct a Store
|
||||
Store() : m_messageEnd(false) {}
|
||||
|
||||
void IsolatedInitialize(const NameValuePairs ¶meters)
|
||||
{
|
||||
m_messageEnd = false;
|
||||
StoreInitialize(parameters);
|
||||
}
|
||||
|
||||
unsigned int NumberOfMessages() const {return m_messageEnd ? 0 : 1;}
|
||||
bool GetNextMessage();
|
||||
unsigned int CopyMessagesTo(BufferedTransformation &target, unsigned int count=UINT_MAX, const std::string &channel=DEFAULT_CHANNEL) const;
|
||||
|
||||
protected:
|
||||
virtual void StoreInitialize(const NameValuePairs ¶meters) =0;
|
||||
|
||||
bool m_messageEnd;
|
||||
};
|
||||
|
||||
/// \brief Implementation of BufferedTransformation's attachment interface
|
||||
/// \details Sink is a cornerstone of the Pipeline trinitiy. Data flows from
|
||||
/// Sources, through Filters, and then terminates in Sinks. The difference
|
||||
/// between a Source and Filter is a Source \a pumps data, while a Filter does
|
||||
/// not. The difference between a Filter and a Sink is a Filter allows an
|
||||
/// attached transformation, while a Sink does not.
|
||||
/// \details A Sink doesnot produce any retrievable output.
|
||||
/// \details See the discussion of BufferedTransformation in cryptlib.h for
|
||||
/// more details.
|
||||
class CRYPTOPP_DLL CRYPTOPP_NO_VTABLE Sink : public BufferedTransformation
|
||||
{
|
||||
public:
|
||||
size_t TransferTo2(BufferedTransformation &target, lword &transferBytes, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true)
|
||||
{CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(transferBytes); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); transferBytes = 0; return 0;}
|
||||
size_t CopyRangeTo2(BufferedTransformation &target, lword &begin, lword end=LWORD_MAX, const std::string &channel=DEFAULT_CHANNEL, bool blocking=true) const
|
||||
{CRYPTOPP_UNUSED(target); CRYPTOPP_UNUSED(begin); CRYPTOPP_UNUSED(end); CRYPTOPP_UNUSED(channel); CRYPTOPP_UNUSED(blocking); return 0;}
|
||||
};
|
||||
|
||||
/// \brief Acts as an input discarding Filter or Sink
|
||||
/// \details The BitBucket discards all input and returns 0 to the caller
|
||||
/// to indicate all data was processed.
|
||||
class CRYPTOPP_DLL BitBucket : public Bufferless<Sink>
|
||||
{
|
||||
public:
|
||||
std::string AlgorithmName() const {return "BitBucket";}
|
||||
void IsolatedInitialize(const NameValuePairs ¶ms)
|
||||
{CRYPTOPP_UNUSED(params);}
|
||||
size_t Put2(const byte *inString, size_t length, int messageEnd, bool blocking)
|
||||
{CRYPTOPP_UNUSED(inString); CRYPTOPP_UNUSED(length); CRYPTOPP_UNUSED(messageEnd); CRYPTOPP_UNUSED(blocking); return 0;}
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#if CRYPTOPP_MSC_VERSION
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
257
wasm_src/smartptr.h
Normal file
257
wasm_src/smartptr.h
Normal file
@ -0,0 +1,257 @@
|
||||
// smartptr.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file smartptr.h
|
||||
/// \brief Classes for automatic resource management
|
||||
|
||||
#ifndef CRYPTOPP_SMARTPTR_H
|
||||
#define CRYPTOPP_SMARTPTR_H
|
||||
|
||||
#include "config.h"
|
||||
#include "stdcpp.h"
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
/// \brief Manages resources for a single object
|
||||
/// \tparam T class or type
|
||||
/// \details \p simple_ptr is used frequently in the library to manage resources and
|
||||
/// ensure cleanup under the RAII pattern (Resource Acquisition Is Initialization).
|
||||
template <class T> class simple_ptr
|
||||
{
|
||||
public:
|
||||
simple_ptr(T *p = NULLPTR) : m_p(p) {}
|
||||
~simple_ptr()
|
||||
{
|
||||
delete m_p;
|
||||
m_p = NULLPTR;
|
||||
}
|
||||
|
||||
T *m_p;
|
||||
};
|
||||
|
||||
/// \brief Pointer that overloads operator ->
|
||||
/// \tparam T class or type
|
||||
/// \details member_ptr is used frequently in the library to avoid the issues related to
|
||||
/// std::auto_ptr in C++11 (deprecated) and std::unique_ptr in C++03 (non-existent).
|
||||
/// \bug <a href="http://github.com/weidai11/cryptopp/issues/48">Issue 48: "Use of auto_ptr
|
||||
/// causes dirty compile under C++11"</a>
|
||||
template <class T> class member_ptr
|
||||
{
|
||||
public:
|
||||
explicit member_ptr(T *p = NULLPTR) : m_p(p) {}
|
||||
|
||||
~member_ptr();
|
||||
|
||||
const T& operator*() const { return *m_p; }
|
||||
T& operator*() { return *m_p; }
|
||||
|
||||
const T* operator->() const { return m_p; }
|
||||
T* operator->() { return m_p; }
|
||||
|
||||
const T* get() const { return m_p; }
|
||||
T* get() { return m_p; }
|
||||
|
||||
T* release()
|
||||
{
|
||||
T *old_p = m_p;
|
||||
m_p = NULLPTR;
|
||||
return old_p;
|
||||
}
|
||||
|
||||
void reset(T *p = NULLPTR);
|
||||
|
||||
protected:
|
||||
member_ptr(const member_ptr<T>& rhs); // copy not allowed
|
||||
void operator=(const member_ptr<T>& rhs); // assignment not allowed
|
||||
|
||||
T *m_p;
|
||||
};
|
||||
|
||||
template <class T> member_ptr<T>::~member_ptr() {delete m_p;}
|
||||
template <class T> void member_ptr<T>::reset(T *p) {delete m_p; m_p = p;}
|
||||
|
||||
// ********************************************************
|
||||
|
||||
/// \brief Value pointer
|
||||
/// \tparam T class or type
|
||||
template<class T> class value_ptr : public member_ptr<T>
|
||||
{
|
||||
public:
|
||||
value_ptr(const T &obj) : member_ptr<T>(new T(obj)) {}
|
||||
value_ptr(T *p = NULLPTR) : member_ptr<T>(p) {}
|
||||
value_ptr(const value_ptr<T>& rhs)
|
||||
: member_ptr<T>(rhs.m_p ? new T(*rhs.m_p) : NULLPTR) {}
|
||||
|
||||
value_ptr<T>& operator=(const value_ptr<T>& rhs);
|
||||
bool operator==(const value_ptr<T>& rhs)
|
||||
{
|
||||
return (!this->m_p && !rhs.m_p) || (this->m_p && rhs.m_p && *this->m_p == *rhs.m_p);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> value_ptr<T>& value_ptr<T>::operator=(const value_ptr<T>& rhs)
|
||||
{
|
||||
T *old_p = this->m_p;
|
||||
this->m_p = rhs.m_p ? new T(*rhs.m_p) : NULLPTR;
|
||||
delete old_p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ********************************************************
|
||||
|
||||
/// \brief A pointer which can be copied and cloned
|
||||
/// \tparam T class or type
|
||||
/// \details \p T should adhere to the \p Clonable interface
|
||||
template<class T> class clonable_ptr : public member_ptr<T>
|
||||
{
|
||||
public:
|
||||
clonable_ptr(const T &obj) : member_ptr<T>(obj.Clone()) {}
|
||||
clonable_ptr(T *p = NULLPTR) : member_ptr<T>(p) {}
|
||||
clonable_ptr(const clonable_ptr<T>& rhs)
|
||||
: member_ptr<T>(rhs.m_p ? rhs.m_p->Clone() : NULLPTR) {}
|
||||
|
||||
clonable_ptr<T>& operator=(const clonable_ptr<T>& rhs);
|
||||
};
|
||||
|
||||
template <class T> clonable_ptr<T>& clonable_ptr<T>::operator=(const clonable_ptr<T>& rhs)
|
||||
{
|
||||
T *old_p = this->m_p;
|
||||
this->m_p = rhs.m_p ? rhs.m_p->Clone() : NULLPTR;
|
||||
delete old_p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ********************************************************
|
||||
|
||||
/// \brief Reference counted pointer
|
||||
/// \tparam T class or type
|
||||
/// \details users should declare \p m_referenceCount as <tt>std::atomic<unsigned></tt>
|
||||
/// (or similar) under C++ 11
|
||||
template<class T> class counted_ptr
|
||||
{
|
||||
public:
|
||||
explicit counted_ptr(T *p = NULLPTR);
|
||||
counted_ptr(const T &r) : m_p(0) {attach(r);}
|
||||
counted_ptr(const counted_ptr<T>& rhs);
|
||||
|
||||
~counted_ptr();
|
||||
|
||||
const T& operator*() const { return *m_p; }
|
||||
T& operator*() { return *m_p; }
|
||||
|
||||
const T* operator->() const { return m_p; }
|
||||
T* operator->() { return get(); }
|
||||
|
||||
const T* get() const { return m_p; }
|
||||
T* get();
|
||||
|
||||
void attach(const T &p);
|
||||
|
||||
counted_ptr<T> & operator=(const counted_ptr<T>& rhs);
|
||||
|
||||
private:
|
||||
T *m_p;
|
||||
};
|
||||
|
||||
template <class T> counted_ptr<T>::counted_ptr(T *p)
|
||||
: m_p(p)
|
||||
{
|
||||
if (m_p)
|
||||
m_p->m_referenceCount = 1;
|
||||
}
|
||||
|
||||
template <class T> counted_ptr<T>::counted_ptr(const counted_ptr<T>& rhs)
|
||||
: m_p(rhs.m_p)
|
||||
{
|
||||
if (m_p)
|
||||
m_p->m_referenceCount++;
|
||||
}
|
||||
|
||||
template <class T> counted_ptr<T>::~counted_ptr()
|
||||
{
|
||||
if (m_p && --m_p->m_referenceCount == 0)
|
||||
delete m_p;
|
||||
}
|
||||
|
||||
template <class T> void counted_ptr<T>::attach(const T &r)
|
||||
{
|
||||
if (m_p && --m_p->m_referenceCount == 0)
|
||||
delete m_p;
|
||||
if (r.m_referenceCount == 0)
|
||||
{
|
||||
m_p = r.clone();
|
||||
m_p->m_referenceCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_p = const_cast<T *>(&r);
|
||||
m_p->m_referenceCount++;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T> T* counted_ptr<T>::get()
|
||||
{
|
||||
if (m_p && m_p->m_referenceCount > 1)
|
||||
{
|
||||
T *temp = m_p->clone();
|
||||
m_p->m_referenceCount--;
|
||||
m_p = temp;
|
||||
m_p->m_referenceCount = 1;
|
||||
}
|
||||
return m_p;
|
||||
}
|
||||
|
||||
template <class T> counted_ptr<T> & counted_ptr<T>::operator=(const counted_ptr<T>& rhs)
|
||||
{
|
||||
if (m_p != rhs.m_p)
|
||||
{
|
||||
if (m_p && --m_p->m_referenceCount == 0)
|
||||
delete m_p;
|
||||
m_p = rhs.m_p;
|
||||
if (m_p)
|
||||
m_p->m_referenceCount++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ********************************************************
|
||||
|
||||
/// \brief Manages resources for an array of objects
|
||||
/// \tparam T class or type
|
||||
template <class T> class vector_member_ptrs
|
||||
{
|
||||
public:
|
||||
/// Construct an arry of \p T
|
||||
/// \param size the size of the array, in elements
|
||||
/// \details If \p T is a Plain Old Dataype (POD), then the array is uninitialized.
|
||||
vector_member_ptrs(size_t size=0)
|
||||
: m_size(size), m_ptr(new member_ptr<T>[size]) {}
|
||||
~vector_member_ptrs()
|
||||
{delete [] this->m_ptr;}
|
||||
|
||||
member_ptr<T>& operator[](size_t index)
|
||||
{CRYPTOPP_ASSERT(index<this->m_size); return this->m_ptr[index];}
|
||||
const member_ptr<T>& operator[](size_t index) const
|
||||
{CRYPTOPP_ASSERT(index<this->m_size); return this->m_ptr[index];}
|
||||
|
||||
size_t size() const {return this->m_size;}
|
||||
void resize(size_t newSize)
|
||||
{
|
||||
member_ptr<T> *newPtr = new member_ptr<T>[newSize];
|
||||
for (size_t i=0; i<this->m_size && i<newSize; i++)
|
||||
newPtr[i].reset(this->m_ptr[i].release());
|
||||
delete [] this->m_ptr;
|
||||
this->m_size = newSize;
|
||||
this->m_ptr = newPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
vector_member_ptrs(const vector_member_ptrs<T> &c); // copy not allowed
|
||||
void operator=(const vector_member_ptrs<T> &x); // assignment not allowed
|
||||
|
||||
size_t m_size;
|
||||
member_ptr<T> *m_ptr;
|
||||
};
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
101
wasm_src/stdcpp.h
Normal file
101
wasm_src/stdcpp.h
Normal file
@ -0,0 +1,101 @@
|
||||
// stdcpp.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file stdcpp.h
|
||||
/// \brief Common C++ header files
|
||||
|
||||
#ifndef CRYPTOPP_STDCPP_H
|
||||
#define CRYPTOPP_STDCPP_H
|
||||
|
||||
#if _MSC_VER >= 1500
|
||||
#define _DO_NOT_DECLARE_INTERLOCKED_INTRINSICS_IN_MEMORY
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <typeinfo>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <new>
|
||||
|
||||
// http://connect.microsoft.com/VisualStudio/feedback/details/1600701/type-info-does-not-compile-with-has-exceptions-0
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1900) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 0)
|
||||
namespace std {
|
||||
using ::type_info;
|
||||
}
|
||||
#endif
|
||||
|
||||
// workaround needed for IBM XLC and debug heaps on AIX
|
||||
#if defined(_AIX) && (defined(__xlc__) || defined(__xlC__) || defined(__ibmxl__))
|
||||
# if defined(__DEBUG_ALLOC__)
|
||||
namespace std {
|
||||
using ::_debug_memset;
|
||||
using ::_debug_memcpy;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// make_unchecked_array_iterator
|
||||
#if _MSC_VER >= 1600
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
#if defined(CRYPTOPP_CXX11_ATOMIC)
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
#if defined(CRYPTOPP_CXX11_SYNCHRONIZATION)
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
#if defined(CRYPTOPP_CXX11_RVALUES)
|
||||
# include <utility>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
|
||||
// It is 2019 and VS2017/Win10 still can't compile a
|
||||
// program that includes <cstddef> without making users
|
||||
// do something special. "Epic fail" comes to mind.
|
||||
// Also see https://github.com/weidai11/cryptopp/issues/781
|
||||
#ifndef _MSC_VER
|
||||
# include <cstddef>
|
||||
#endif
|
||||
|
||||
// uintptr_t and ptrdiff_t
|
||||
#if defined(__SUNPRO_CC)
|
||||
# if (__SUNPRO_CC >= 0x5100)
|
||||
# include <stdint.h>
|
||||
# endif
|
||||
#elif defined(_MSC_VER)
|
||||
# if (_MSC_VER >= 1700)
|
||||
# include <stdint.h>
|
||||
# else
|
||||
# include <stddef.h>
|
||||
# endif
|
||||
#elif (__cplusplus < 201103L)
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
// workaround needed on Sun Studio 12u1 Sun C++ 5.10 SunOS_i386 128229-02 2009/09/21
|
||||
#ifdef CRYPTOPP_INCLUDE_VECTOR_CC
|
||||
# include <vector.cc>
|
||||
#endif
|
||||
|
||||
// C++Builder's standard library (Dinkumware) do not have C's global log() function
|
||||
// https://github.com/weidai11/cryptopp/issues/520
|
||||
#ifdef __BORLANDC__
|
||||
using std::log;
|
||||
#endif
|
||||
|
||||
#endif // CRYPTOPP_STDCPP_H
|
225
wasm_src/words.h
Normal file
225
wasm_src/words.h
Normal file
@ -0,0 +1,225 @@
|
||||
// words.h - originally written and placed in the public domain by Wei Dai
|
||||
|
||||
/// \file words.h
|
||||
/// \brief Support functions for word operations
|
||||
|
||||
#ifndef CRYPTOPP_WORDS_H
|
||||
#define CRYPTOPP_WORDS_H
|
||||
|
||||
#include "config.h"
|
||||
#include "misc.h"
|
||||
|
||||
NAMESPACE_BEGIN(CryptoPP)
|
||||
|
||||
/// \brief Count the number of words
|
||||
/// \param x word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \return number of words used in the array.
|
||||
/// \details CountWords counts the number of words in a word array.
|
||||
/// Leading 0-words are not included in the count.
|
||||
/// \since Crypto++ 1.0
|
||||
inline size_t CountWords(const word *x, size_t n)
|
||||
{
|
||||
while (n && x[n-1]==0)
|
||||
n--;
|
||||
return n;
|
||||
}
|
||||
|
||||
/// \brief Set the value of words
|
||||
/// \param r word array
|
||||
/// \param a value
|
||||
/// \param n size of the word array, in elements
|
||||
/// \details SetWords sets all elements in the word array to the
|
||||
/// specified value.
|
||||
/// \since Crypto++ 1.0
|
||||
inline void SetWords(word *r, word a, size_t n)
|
||||
{
|
||||
for (size_t i=0; i<n; i++)
|
||||
r[i] = a;
|
||||
}
|
||||
|
||||
/// \brief Copy word array
|
||||
/// \param r destination word array
|
||||
/// \param a source word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \details CopyWords copies the source word array to the destination
|
||||
/// word array.
|
||||
/// \since Crypto++ 1.0
|
||||
inline void CopyWords(word *r, const word *a, size_t n)
|
||||
{
|
||||
if (r != a)
|
||||
#if CRYPTOPP_MSC_VERSION
|
||||
memcpy_s(r, n*WORD_SIZE, a, n*WORD_SIZE);
|
||||
#else
|
||||
memcpy(r, a, n*WORD_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// \brief XOR word arrays
|
||||
/// \param r destination word array
|
||||
/// \param a first source word array
|
||||
/// \param b second source word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \details XorWords XORs the two source word arrays and copies the
|
||||
/// result to the destination word array.
|
||||
/// \since Crypto++ 1.0
|
||||
inline void XorWords(word *r, const word *a, const word *b, size_t n)
|
||||
{
|
||||
for (size_t i=0; i<n; i++)
|
||||
r[i] = a[i] ^ b[i];
|
||||
}
|
||||
|
||||
/// \brief XOR word arrays
|
||||
/// \param r destination word array
|
||||
/// \param a source word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \details XorWords XORs the source word array with the
|
||||
/// destination word array.
|
||||
/// \since Crypto++ 1.0
|
||||
inline void XorWords(word *r, const word *a, size_t n)
|
||||
{
|
||||
for (size_t i=0; i<n; i++)
|
||||
r[i] ^= a[i];
|
||||
}
|
||||
|
||||
/// \brief AND word arrays
|
||||
/// \param r destination word array
|
||||
/// \param a first source word array
|
||||
/// \param b second source word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \details AndWords ANDs the two source word arrays and copies the
|
||||
/// result to the destination word array.
|
||||
/// \since Crypto++ 1.0
|
||||
inline void AndWords(word *r, const word *a, const word *b, size_t n)
|
||||
{
|
||||
for (size_t i=0; i<n; i++)
|
||||
r[i] = a[i] & b[i];
|
||||
}
|
||||
|
||||
/// \brief AND word arrays
|
||||
/// \param r destination word array
|
||||
/// \param a source word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \details AndWords ANDs the source word array with the
|
||||
/// destination word array.
|
||||
/// \since Crypto++ 1.0
|
||||
inline void AndWords(word *r, const word *a, size_t n)
|
||||
{
|
||||
for (size_t i=0; i<n; i++)
|
||||
r[i] &= a[i];
|
||||
}
|
||||
|
||||
/// \brief OR word arrays
|
||||
/// \param r destination word array
|
||||
/// \param a first source word array
|
||||
/// \param b second source word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \details OrWords ORs the two source word arrays and copies the
|
||||
/// result to the destination word array.
|
||||
/// \since Crypto++ 1.0
|
||||
inline void OrWords(word *r, const word *a, const word *b, size_t n)
|
||||
{
|
||||
for (size_t i=0; i<n; i++)
|
||||
r[i] = a[i] | b[i];
|
||||
}
|
||||
|
||||
/// \brief OR word arrays
|
||||
/// \param r destination word array
|
||||
/// \param a source word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \details OrWords ORs the source word array with the
|
||||
/// destination word array.
|
||||
/// \since Crypto++ 1.0
|
||||
inline void OrWords(word *r, const word *a, size_t n)
|
||||
{
|
||||
for (size_t i=0; i<n; i++)
|
||||
r[i] |= a[i];
|
||||
}
|
||||
|
||||
/// \brief Left shift word array
|
||||
/// \param r word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \param shiftBits number of bits to shift
|
||||
/// \return word shifted out
|
||||
/// \details ShiftWordsLeftByBits shifts the word array left by
|
||||
/// shiftBits. ShiftWordsLeftByBits shifts bits out on the left;
|
||||
/// it does not extend the array.
|
||||
/// \note shiftBits must be less than WORD_BITS.
|
||||
/// \since Crypto++ 1.0
|
||||
inline word ShiftWordsLeftByBits(word *r, size_t n, unsigned int shiftBits)
|
||||
{
|
||||
CRYPTOPP_ASSERT (shiftBits<WORD_BITS);
|
||||
word u, carry=0;
|
||||
if (shiftBits)
|
||||
for (size_t i=0; i<n; i++)
|
||||
{
|
||||
u = r[i];
|
||||
r[i] = (u << shiftBits) | carry;
|
||||
carry = u >> (WORD_BITS-shiftBits);
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
/// \brief Right shift word array
|
||||
/// \param r word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \param shiftBits number of bits to shift
|
||||
/// \return word shifted out
|
||||
/// \details ShiftWordsRightByBits shifts the word array shight by
|
||||
/// shiftBits. ShiftWordsRightByBits shifts bits out on the right.
|
||||
/// \note shiftBits must be less than WORD_BITS.
|
||||
/// \since Crypto++ 1.0
|
||||
inline word ShiftWordsRightByBits(word *r, size_t n, unsigned int shiftBits)
|
||||
{
|
||||
CRYPTOPP_ASSERT (shiftBits<WORD_BITS);
|
||||
word u, carry=0;
|
||||
if (shiftBits)
|
||||
for (size_t i=n; i>0; i--)
|
||||
{
|
||||
u = r[i-1];
|
||||
r[i-1] = (u >> shiftBits) | carry;
|
||||
carry = u << (WORD_BITS-shiftBits);
|
||||
}
|
||||
return carry;
|
||||
}
|
||||
|
||||
/// \brief Left shift word array
|
||||
/// \param r word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \param shiftWords number of words to shift
|
||||
/// \details ShiftWordsLeftByWords shifts the word array left by
|
||||
/// shiftWords. ShiftWordsLeftByWords shifts bits out on the left;
|
||||
/// it does not extend the array.
|
||||
/// \since Crypto++ 1.0
|
||||
inline void ShiftWordsLeftByWords(word *r, size_t n, size_t shiftWords)
|
||||
{
|
||||
shiftWords = STDMIN(shiftWords, n);
|
||||
if (shiftWords)
|
||||
{
|
||||
for (size_t i=n-1; i>=shiftWords; i--)
|
||||
r[i] = r[i-shiftWords];
|
||||
SetWords(r, 0, shiftWords);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Right shift word array
|
||||
/// \param r word array
|
||||
/// \param n size of the word array, in elements
|
||||
/// \param shiftWords number of words to shift
|
||||
/// \details ShiftWordsRightByWords shifts the word array right by
|
||||
/// shiftWords. ShiftWordsRightByWords shifts bits out on the right.
|
||||
/// \since Crypto++ 1.0
|
||||
inline void ShiftWordsRightByWords(word *r, size_t n, size_t shiftWords)
|
||||
{
|
||||
shiftWords = STDMIN(shiftWords, n);
|
||||
if (shiftWords)
|
||||
{
|
||||
for (size_t i=0; i+shiftWords<n; i++)
|
||||
r[i] = r[i+shiftWords];
|
||||
SetWords(r+n-shiftWords, 0, shiftWords);
|
||||
}
|
||||
}
|
||||
|
||||
NAMESPACE_END
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user