/* * Aegis Bitcoin Wallet - The secure Bitcoin wallet for Android * Copyright 2014 Bojan Simic and specularX.co, designed by Reuven Yamrom * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.aegiswallet.test.crypto; import android.test.InstrumentationTestCase; import android.util.Log; import com.aegiswallet.helpers.secretshare.SecretShare; import com.aegiswallet.utils.WalletUtils; import java.math.BigInteger; import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; /** * Created by bsimic on 5/5/14. */ public class ShamirTest extends InstrumentationTestCase { private String TAG = this.getClass().getName(); final int n = 3; final int k = 2; BigInteger prime = null; public void test() throws Exception { SecureRandom r = new SecureRandom(); BigInteger secret = new BigInteger(256, r); prime = SecretShare.createAppropriateModulusForSecret(secret); SecretShare.PublicInfo publicInfo = new SecretShare.PublicInfo(n, k, prime, "test one"); SecretShare secretShare = new SecretShare(publicInfo); SecretShare.SplitSecretOutput splitSecretOutput = secretShare.split(secret, r); BigInteger recon = subtestReconstruction(splitSecretOutput.getShareInfos()); assertEquals(secret, recon); } public void test10Iterations() { for (int i = 0; i <= 10; i++) { SecureRandom r = new SecureRandom(); BigInteger secret = new BigInteger(256, r); BigInteger primePad = new BigInteger(128, r); //BigInteger newPrime = primePad.add(secret); BigInteger newPrime = BigInteger.probablePrime(256 + 64, r); SecretShare.PublicInfo publicInfo = new SecretShare.PublicInfo(n, k, newPrime, "test " + i); SecretShare secretShare = new SecretShare(publicInfo); SecretShare.SplitSecretOutput splitSecretOutput = secretShare.split(secret, r); Log.d(TAG, i + " " + splitSecretOutput.debugDump()); Log.d(TAG, "Solving... " + i); BigInteger recon = subtestReconstruction(splitSecretOutput.getShareInfos()); assertEquals(secret, recon); } } public void testReconWithTwo() { SecureRandom r = new SecureRandom(); BigInteger secret = new BigInteger(256, r); prime = SecretShare.createAppropriateModulusForSecret(secret); SecretShare.PublicInfo publicInfo = new SecretShare.PublicInfo(n, k, prime, "test one"); SecretShare secretShare = new SecretShare(publicInfo); SecretShare.SplitSecretOutput splitSecretOutput = secretShare.split(secret, r); Log.d(TAG, splitSecretOutput.debugDump()); Log.d(TAG, "Solving using shares..."); //Removing 2 of the shares to show that they the result fails. List<SecretShare.ShareInfo> infos = splitSecretOutput.getShareInfos(); List<SecretShare.ShareInfo> newShares = new ArrayList<SecretShare.ShareInfo>(); SecretShare.PublicInfo publicInfo1 = new SecretShare.PublicInfo(3, 2, null, null); SecretShare.PublicInfo publicInfo2 = new SecretShare.PublicInfo(3, 2, null, null); SecretShare.ShareInfo shareInfoOne = new SecretShare.ShareInfo(1, infos.get(0).getShare(), publicInfo1); SecretShare.ShareInfo shareInfoThree = new SecretShare.ShareInfo(3, infos.get(2).getShare(), publicInfo2); newShares.add(shareInfoOne); newShares.add(shareInfoThree); BigInteger recon = subtestReconstruction(newShares); assertEquals(secret, recon); } public void testSecretRecovery() { String k1 = "1:7777330194881803291642355287239194720526881768387740038069905695006411010950"; String k2 = "2:7777330194881803291642355287239194720571518620826621934932528030228401280839"; String k3 = "3:7777330194881803291642355287239194720616155473265503831795150365450391550728"; String original = "7777330194881803291642355287239194720482244915948858141207283359784420741061"; BigInteger secret = WalletUtils.generateSecretFromStrings(k1, k2, k3); Log.d(TAG, "Secret is: " + secret); assertEquals(secret.toString(), original); } public void testSecretRecovery2Keys() { String k1 = "1:7777330194881803291642355287239194720526881768387740038069905695006411010950"; String k3 = "3:7777330194881803291642355287239194720616155473265503831795150365450391550728"; String original = "7777330194881803291642355287239194720482244915948858141207283359784420741061"; BigInteger secret = WalletUtils.generateSecretFromStrings(k1, null, k3); Log.d(TAG, "Secret is: " + secret); assertEquals(secret.toString(), original); } public void testSecretRecovery2KeysAlternate() { String k1 = "1:7777330194881803291642355287239194720526881768387740038069905695006411010950"; String k2 = "2:7777330194881803291642355287239194720571518620826621934932528030228401280839"; String original = "7777330194881803291642355287239194720482244915948858141207283359784420741061"; BigInteger secret = WalletUtils.generateSecretFromStrings(k1, k2, null); Log.d(TAG, "Secret is: " + secret); assertEquals(secret.toString(), original); } public void testSecretRecovery2KeysAlternateAgain() { String k2 = "2:7777330194881803291642355287239194720571518620826621934932528030228401280839"; String k3 = "3:7777330194881803291642355287239194720616155473265503831795150365450391550728"; String original = "7777330194881803291642355287239194720482244915948858141207283359784420741061"; BigInteger secret = WalletUtils.generateSecretFromStrings(null, k2, k3); Log.d(TAG, "Secret is: " + secret); assertEquals(secret.toString(), original); } private BigInteger subtestReconstruction(List<SecretShare.ShareInfo> shares) { if (true) { subtestAllCombinations(shares); } // pick the first share's public info: SecretShare.PublicInfo publicInfo = shares.get(0).getPublicInfo(); // create a new solver from just the public info: SecretShare solver = new SecretShare(publicInfo); // pick some of the shares List<SecretShare.ShareInfo> usetheseshares = new ArrayList<SecretShare.ShareInfo>(); for (int i = 0, max = publicInfo.getK(); i < max; i++) { usetheseshares.add(shares.get(i)); } SecretShare.CombineOutput solved = solver.combine(usetheseshares); return solved.getSecret(); } private void subtestAllCombinations(List<SecretShare.ShareInfo> shares) { // pick the first share's public info: SecretShare.PublicInfo publicInfo = shares.get(0).getPublicInfo(); // create a new solver from just the public info: SecretShare solver = new SecretShare(publicInfo); BigInteger secret = solver.combineParanoid(shares); assertNotNull(secret); } }