All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.com.ionic.sdk.crypto.shamir.Scheme Maven / Gradle / Ivy

Go to download

The Ionic Java SDK provides an easy-to-use interface to the Ionic Platform.

There is a newer version: 2.9.0
Show newest version
package com.ionic.sdk.crypto.shamir;

import com.ionic.sdk.error.IonicException;
import com.ionic.sdk.error.SdkError;

import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * An implementation of Shamir's Secret Sharing,
 * allowing for the splitting of a secret into multiple parts, some or all of which are needed to recover the original
 * secret.
 */
public final class Scheme {

    /**
     * The number of parts into which the input secret should be split.
     */
    private final int n;

    /**
     * The number of parts from which the input secret should be recoverable.
     */
    private final int k;

    /**
     * A source of randomness to use in the generation of the split polynomial.
     */
    private final SecureRandom random;

    /**
     * Construct an object to be used in the splitting and recovery of a secret.
     * 

* The variable k must be at least 1, and the variable n must be at least as large as k. Additionally, n * is limited to a maximum of 255, for performance. * * @param n the number of parts into which the input secret should be split * @param k the number of parts from which the input secret should be recoverable * @throws IonicException on illegal inputs */ public Scheme(final int n, final int k) throws IonicException { final boolean invalid = ((k < 1) || (n < k) || (n > MAX_N)); if (invalid) { throw new IonicException(SdkError.ISAGENT_INVALIDVALUE, new IllegalArgumentException(String.format("N = %d, K = %d", n, k))); } this.n = n; this.k = k; this.random = new SecureRandom(); } /** * Split a secret into multiple parts. * * @param secret the original secret * @return a set of polynomial components, which may be used at a later time to recover the secret */ public List split(final byte[] secret) { // generate part values final byte[][] values = new byte[n][secret.length]; for (int i = 0; i < secret.length; ++i) { // for each byte, generate a random polynomial, p final byte[] p = GF256.generate(random, k - 1, secret[i]); for (int x = 1; x <= n; ++x) { // each part's byte is p(partId) values[x - 1][i] = GF256.eval(p, (byte) x); } } // return as a set of objects final List parts = new ArrayList(n); for (int i = 0; i < values.length; ++i) { final byte[] value = values[i]; final byte[] valueWrapped = new byte[value.length + CRYPTOPP_OFFSET]; ByteBuffer.wrap(valueWrapped, 0, CRYPTOPP_OFFSET).putInt(i + 1); System.arraycopy(value, 0, valueWrapped, CRYPTOPP_OFFSET, value.length); parts.add(valueWrapped); } return Collections.unmodifiableList(parts); } /** * Recover the original secret from the polynomial components. * * @param parts the polynomial components * @param length the size of the secret to be reconstituted * @return the original secret, reconstituted from the input components */ public byte[] join(final Collection parts, final int length) { //java.util.logging.Logger.getLogger(getClass().getName()).finest( // String.format("JOIN %d PARTS, LENGTH %d", parts.size(), length)); //final int[] lengths = getLengths(parts.values()); final byte[] secret = new byte[length]; for (int i = 0; i < secret.length; i++) { final byte[][] points = new byte[parts.size()][2]; int j = 0; for (final byte[] value : parts) { // here is where we will strip off the cryptopp padding final int channel = ByteBuffer.wrap(value, 0, CRYPTOPP_OFFSET).getInt(); final byte[] valueUnwrapped = new byte[value.length - CRYPTOPP_OFFSET]; System.arraycopy(value, CRYPTOPP_OFFSET, valueUnwrapped, 0, valueUnwrapped.length); points[j][0] = Integer.valueOf(channel).byteValue(); points[j][1] = valueUnwrapped[i]; j++; } secret[i] = GF256.interpolate(points); } return secret; } /* * Calculate the lengths of the input value collection. * * @param values the collection of byte arrays representing the polynomial components * @return a corresponding array containing the calculated lengths of the input components */ /* private int[] getLengths(final Collection values) { final Set lengths = new TreeSet(); for (final byte[] value : values) { lengths.add(value.length); } final int[] lengthsArray = new int[lengths.size()]; int index = -1; for (final Integer length : lengths) { lengthsArray[++index] = length; } return lengthsArray; } */ /** * The "cryptopp" implementation prepends the share data with a 4-byte block containing the channel number. */ private static final int CRYPTOPP_OFFSET = 4; /** * Limit the computational complexity of our implementation. */ private static final int MAX_N = 255; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy