Algorithm for elliptic curve point compression












8















I'm using Javascript to generate elliptic curves for use in a cryptographic messaging app based on this example code http://www-cs-students.stanford.edu/~tjw/jsbn/ecdh.html



The public keys will be quite large and I know it's possible to compress them, but I've been unable to find a Javascript or outline algorithm to do this. Here's an article http://nmav.gnutls.org/2012/01/do-we-need-elliptic-curve-point.html that outlines the maths.










share|improve this question

























  • For ECDH you don't actually need point compression. In many cases it's sufficient to only use a single coordinate in the first place.

    – CodesInChaos
    Jun 18 '13 at 21:17






  • 1





    @CodesInChaos Can you explain that a little bit more ? or perhaps do you have a reference ? Thanks.

    – Ian Purton
    Jun 20 '13 at 6:14











  • Looks like he mixed together result of calculation and storage of public keys. In most standards x coordinate of resulting ECDH point is used as source for shared secret.

    – Nickolay Olshevsky
    Jun 20 '13 at 10:56
















8















I'm using Javascript to generate elliptic curves for use in a cryptographic messaging app based on this example code http://www-cs-students.stanford.edu/~tjw/jsbn/ecdh.html



The public keys will be quite large and I know it's possible to compress them, but I've been unable to find a Javascript or outline algorithm to do this. Here's an article http://nmav.gnutls.org/2012/01/do-we-need-elliptic-curve-point.html that outlines the maths.










share|improve this question

























  • For ECDH you don't actually need point compression. In many cases it's sufficient to only use a single coordinate in the first place.

    – CodesInChaos
    Jun 18 '13 at 21:17






  • 1





    @CodesInChaos Can you explain that a little bit more ? or perhaps do you have a reference ? Thanks.

    – Ian Purton
    Jun 20 '13 at 6:14











  • Looks like he mixed together result of calculation and storage of public keys. In most standards x coordinate of resulting ECDH point is used as source for shared secret.

    – Nickolay Olshevsky
    Jun 20 '13 at 10:56














8












8








8


1






I'm using Javascript to generate elliptic curves for use in a cryptographic messaging app based on this example code http://www-cs-students.stanford.edu/~tjw/jsbn/ecdh.html



The public keys will be quite large and I know it's possible to compress them, but I've been unable to find a Javascript or outline algorithm to do this. Here's an article http://nmav.gnutls.org/2012/01/do-we-need-elliptic-curve-point.html that outlines the maths.










share|improve this question
















I'm using Javascript to generate elliptic curves for use in a cryptographic messaging app based on this example code http://www-cs-students.stanford.edu/~tjw/jsbn/ecdh.html



The public keys will be quite large and I know it's possible to compress them, but I've been unable to find a Javascript or outline algorithm to do this. Here's an article http://nmav.gnutls.org/2012/01/do-we-need-elliptic-curve-point.html that outlines the maths.







javascript cryptography elliptic-curve






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jun 18 '13 at 14:30









vcsjones

106k22243253




106k22243253










asked Jun 18 '13 at 14:28









Ian PurtonIan Purton

11.7k21622




11.7k21622













  • For ECDH you don't actually need point compression. In many cases it's sufficient to only use a single coordinate in the first place.

    – CodesInChaos
    Jun 18 '13 at 21:17






  • 1





    @CodesInChaos Can you explain that a little bit more ? or perhaps do you have a reference ? Thanks.

    – Ian Purton
    Jun 20 '13 at 6:14











  • Looks like he mixed together result of calculation and storage of public keys. In most standards x coordinate of resulting ECDH point is used as source for shared secret.

    – Nickolay Olshevsky
    Jun 20 '13 at 10:56



















  • For ECDH you don't actually need point compression. In many cases it's sufficient to only use a single coordinate in the first place.

    – CodesInChaos
    Jun 18 '13 at 21:17






  • 1





    @CodesInChaos Can you explain that a little bit more ? or perhaps do you have a reference ? Thanks.

    – Ian Purton
    Jun 20 '13 at 6:14











  • Looks like he mixed together result of calculation and storage of public keys. In most standards x coordinate of resulting ECDH point is used as source for shared secret.

    – Nickolay Olshevsky
    Jun 20 '13 at 10:56

















For ECDH you don't actually need point compression. In many cases it's sufficient to only use a single coordinate in the first place.

– CodesInChaos
Jun 18 '13 at 21:17





For ECDH you don't actually need point compression. In many cases it's sufficient to only use a single coordinate in the first place.

– CodesInChaos
Jun 18 '13 at 21:17




1




1





@CodesInChaos Can you explain that a little bit more ? or perhaps do you have a reference ? Thanks.

– Ian Purton
Jun 20 '13 at 6:14





@CodesInChaos Can you explain that a little bit more ? or perhaps do you have a reference ? Thanks.

– Ian Purton
Jun 20 '13 at 6:14













Looks like he mixed together result of calculation and storage of public keys. In most standards x coordinate of resulting ECDH point is used as source for shared secret.

– Nickolay Olshevsky
Jun 20 '13 at 10:56





Looks like he mixed together result of calculation and storage of public keys. In most standards x coordinate of resulting ECDH point is used as source for shared secret.

– Nickolay Olshevsky
Jun 20 '13 at 10:56












5 Answers
5






active

oldest

votes


















5














I imagine they'll be increased interest in a JavaScript elliptic curve point compression solution, with WebCrypto support filtering into browsers.

I'll use the NIST curves as the example, because these the ones I had to deal with when importing a compressed public key into WebCrypto.



Curves and their primes
NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1
NIST P-384 (secp384r1) 2^384 - 2^128 - 2^96 + 2^32 - 1
NIST P-521 (secp521r1) 2^521 - 1


These prime numbers all satisfy the equation, p mod 4 === 3

What this means is you can skip the somewhat complex general purpose Tonelli-Shanks algorithm, and use a simple identity to find the square roots.



First, the compression part of 'point compression' is very simple. Record the sign of Y, then discard the value of Y.



/**
* Point compress elliptic curve key
* @param {Uint8Array} x component
* @param {Uint8Array} y component
* @return {Uint8Array} Compressed representation
*/
function ECPointCompress( x, y )
{
const out = new Uint8Array( x.length + 1 );

out[0] = 2 + ( y[ y.length-1 ] & 1 );
out.set( x, 1 );

return out;
}


Decompression involves looking up the square root, then correcting depending on the Y parity bit.
This function depends on a JavaScript big integer library which exposes the following functions: add, sub, multiply, pow, modPow.



// Consts for P256 curve. Adjust accordingly
const two = new bigInt(2),
// 115792089210356248762697446949407573530086143415290314195533631308867097853951
prime = two.pow(256).sub( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).sub(1),
b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
// Pre-computed value, or literal
pIdent = prime.add(1).divide(4); // 28948022302589062190674361737351893382521535853822578548883407827216774463488


/**
* Point decompress NIST curve
* @param {Uint8Array} Compressed representation
* @return {Object} Explicit x & y
*/
function ECPointDecompress( comp )
{
const signY = comp[0] - 2, // This value must be 2 or 3. 4 indicates an uncompressed key, and anything else is invalid.
x = comp.subarray(1),
// Import x into bigInt library
xBig = new bigInt( x );

// y^2 = x^3 - 3x + b
var yBig = xBig.pow(3).sub( xBig.multiply(3) ).add( b ).modPow( pIdent, prime );

// If the parity doesn't match it's the *other* root
if( yBig.mod(2) !== signY )
{
// y = prime - y
yBig = prime.sub( yBig );
}

return {
x: x,
y: yBig.toUint8Array()
};
}





share|improve this answer





















  • 1





    note that sub method has changed to subtract

    – Nicolas Del Valle
    Jul 1 '16 at 2:46













  • This is an excellent response which has not been sufficiently valued. @Adria, thank you!

    – denis bider
    May 11 '17 at 13:29



















0














It would be difficult to patent a methematical formula alone. The use of a quadratic equation y = sqrt(x^3+ax+b) can't be patented, and if it is, cannot be protected. One can certainly claim prior art from Diophantes (200-298 AD). and the work around Hall conjecture (circa 1971) about the smallest absolute difference betwwen a square and a cube |y^2 - x^3| being rarely less than x. Rewrite it y^2 - x^3 = ax-b with x < b/a and remark that solutions in modular groups would help reduce the amount of brute force search in integers.



What is patented is the bit which helps to figure out the sign of y. This bit can be used to discriminate the largest of the solution from (y and M-y), or the positive solution from (y, -y), depending the standards you look at.



But since the patent has been accepted, you need to seek a legal advice.



As a reputable cryptographer well versed in the skills of the art Dr. Dan Bernstein points judiciously ( http://cr.yp.to/ecdh/patents.html ), the idea of recomputing y from x is mentioned in Miller 1986 as a triviality to reduce the footprint of elliptic curves points in memory-based systems.



A lawyer specialized in patent claims could help you to assess if the patent still applies if you do not use a normal basis as a representation of the point coordinates, or in the case of ecc in gf(p), or if you do not use a bit to recode the compressed value of y, e.g. when choosing the randomness k, P1(x1,y1) and computing P2(x2,y2) = [k]P1 until tr(y1) == tr(y2) removes the ambiguity (a little bit CPU costly, but why not ?).



Alternatively, you can point that the resolution of the quadratic formula is evidently more costly than the few bits saved on a communication channels and this patent is not useful at all, and even damaging for the environment by suggesting the replacement of 6 picowatts of transmission costs by 2 miliwatts of CPU costs (To be acceptable, a patent submission must be new, non-trivial and useful). Then you find a crooked lawyer preferably in California and for sure, there will be a local judge to award you a few $billions for the damages caused to the environment, for the distress caused to your programming skills and to your wallet considering the resulting delays in the release of your valuable application.



Else, as suggested in another post, you go for a licensing solution.



If your application is for the US government, you need another lawyer to assess if this patent and the way you plan to use it is already part of the licences purchased by NSA in the context of the "Suite B" of algorithms, in which case the license could already be payed for by the people of the US.






share|improve this answer

































    0














    Compression of elliptic curve points is patented by Certicom, so you should not use it without the license, generally.



    Update: Certicom's patent was expired in 2014, according to the comment by denis bider below.






    share|improve this answer


























    • I don't want to get into politics generally but which jurisdiction allows software patents ?

      – Ian Purton
      Jun 18 '13 at 14:45











    • Almost every, including USA. You can read more on ECC patents on en.wikipedia.org/wiki/ECC_patents

      – Nickolay Olshevsky
      Jun 18 '13 at 14:46











    • Perhaps the USA, but nto the Eu. en.wikipedia.org/wiki/Software_patent In Europe, "computer programs as such" are excluded from patentability and European Patent Office policy is consequently that a program for a computer is not patentable if it does not have the potential to cause a "further technical effect" beyond the inherent technical interactions between hardware and software.

      – Ian Purton
      Jun 18 '13 at 14:50













    • Actually patented not the computer program, but mathematic method. Anyway, I'm not a specialist in European/USA patent laws, just wanted to warn you. In most interent standards compressed points are not supported just because of that stupid patent.

      – Nickolay Olshevsky
      Jun 18 '13 at 15:08











    • Thanks, I appreciate the heads up.

      – Ian Purton
      Jun 20 '13 at 6:09



















    0














    Code for converting bitcoin compressed public key (ECDSA public key) to an 65 bytes of an uncompressed public key, using secp256k1 curve consts, with javascript big integer library latest version 1.6.36, and it can work with hex string directly



    const bigInt = require("big-integer");

    function pad_with_zeroes(number, length) {
    var retval = '' + number;
    while (retval.length < length) {
    retval = '0' + retval;
    }
    return retval;
    }

    // Consts for secp256k1 curve. Adjust accordingly
    // https://en.bitcoin.it/wiki/Secp256k1
    const prime = new bigInt('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16),
    pIdent = prime.add(1).divide(4);

    /**
    * Point decompress secp256k1 curve
    * @param {string} Compressed representation in hex string
    * @return {string} Uncompressed representation in hex string
    */
    function ECPointDecompress( comp ) {
    var signY = new Number(comp[1]) - 2;
    var x = new bigInt(comp.substring(2), 16);
    // y mod p = +-(x^3 + 7)^((p+1)/4) mod p
    var y = x.modPow(3, prime).add(7).mod(prime).modPow( pIdent, prime );
    // If the parity doesn't match it's the *other* root
    if( y.mod(2).toJSNumber() !== signY ) {
    // y = prime - y
    y = prime.subtract( y );
    }
    return '04' + pad_with_zeroes(x.toString(16), 64) + pad_with_zeroes(y.toString(16), 64);
    }


    Example with private key: 55255657523dd1c65a77d3cb53fcd050bf7fc2c11bb0bb6edabdbd41ea51f641



    ECPointDecompress('0314fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267')


    returns: '0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf'






    share|improve this answer































      0














      code for ECPointDecompress above from @Adria is unfortunately outdated, it is using a very old version of JavaScript big integer library



      I rewrite ECPointDecompress with big integer library latest version 1.6.36, and it can work with hex string directly, do not need to use Uint8Array:



      const bigInt = require("big-integer");

      // Consts for P256 curve. Adjust accordingly
      const two = new bigInt(2),
      // 115792089210356248762697446949407573530086143415290314195533631308867097853951
      prime = two.pow(256).subtract( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).subtract(1),
      b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
      // Pre-computed value, or literal
      // 28948022302589062190674361737351893382521535853822578548883407827216774463488
      pIdent = prime.add(1).divide(4);

      function pad_with_zeroes(number, length) {
      var retval = '' + number;
      while (retval.length < length) {
      retval = '0' + retval;
      }
      return retval;
      }

      /**
      * Point decompress NIST curve
      * @param {string} Compressed representation in hex string
      * @return {string} Uncompressed representation in hex string
      */
      function ECPointDecompress( comp ) {
      var signY = new Number(comp[1]) - 2;
      var x = new bigInt(comp.substring(2), 16);
      // y^2 = x^3 - 3x + b
      var y = x.pow(3).subtract( x.multiply(3) ).add( b ).modPow( pIdent, prime );
      // If the parity doesn't match it's the *other* root
      if( y.mod(2).toJSNumber() !== signY ) {
      // y = prime - y
      y = prime.subtract( y );
      }
      return '04' + pad_with_zeroes(x.toString(16), 64) + pad_with_zeroes(y.toString(16), 64);
      }


      This can be used to convert compressed public key (ECDSA public key) to an 65 bytes of an uncompressed public key, but note that bitcoin's compressed public key is created using secp256k1 curve, which is different to the curve that we used in this code: NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1



      Therefore, above code can not be used to convert bitcoin's compressed public key, looking for converter of bitcoin compressed public key with secp256k1 curve consts, refer to https://stackoverflow.com/a/53480175/5630352



      Examples:



      ECPointDecompress('030ce2995c738e2320a5dea2df51b99d88bc5dd38356ba72e51ecc0ca660ca4593')


      returns: '040ce2995c738e2320a5dea2df51b99d88bc5dd38356ba72e51ecc0ca660ca45936215a67f6e3fa1d72f6ef46aa2b7481991427b8764ff90447c6215d8dc931773'



      ECPointDecompress('0267bc6cae41a4579cda2556818bc942a38321cad961028bc74459f36ddca71e0e')


      returns: '0467bc6cae41a4579cda2556818bc942a38321cad961028bc74459f36ddca71e0e7c52f0e9f82bd1b2ba81935ba125cb1030d1ade1bd0306b3579a951418b858e8'






      share|improve this answer


























        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f17171542%2falgorithm-for-elliptic-curve-point-compression%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        5 Answers
        5






        active

        oldest

        votes








        5 Answers
        5






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        5














        I imagine they'll be increased interest in a JavaScript elliptic curve point compression solution, with WebCrypto support filtering into browsers.

        I'll use the NIST curves as the example, because these the ones I had to deal with when importing a compressed public key into WebCrypto.



        Curves and their primes
        NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1
        NIST P-384 (secp384r1) 2^384 - 2^128 - 2^96 + 2^32 - 1
        NIST P-521 (secp521r1) 2^521 - 1


        These prime numbers all satisfy the equation, p mod 4 === 3

        What this means is you can skip the somewhat complex general purpose Tonelli-Shanks algorithm, and use a simple identity to find the square roots.



        First, the compression part of 'point compression' is very simple. Record the sign of Y, then discard the value of Y.



        /**
        * Point compress elliptic curve key
        * @param {Uint8Array} x component
        * @param {Uint8Array} y component
        * @return {Uint8Array} Compressed representation
        */
        function ECPointCompress( x, y )
        {
        const out = new Uint8Array( x.length + 1 );

        out[0] = 2 + ( y[ y.length-1 ] & 1 );
        out.set( x, 1 );

        return out;
        }


        Decompression involves looking up the square root, then correcting depending on the Y parity bit.
        This function depends on a JavaScript big integer library which exposes the following functions: add, sub, multiply, pow, modPow.



        // Consts for P256 curve. Adjust accordingly
        const two = new bigInt(2),
        // 115792089210356248762697446949407573530086143415290314195533631308867097853951
        prime = two.pow(256).sub( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).sub(1),
        b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
        // Pre-computed value, or literal
        pIdent = prime.add(1).divide(4); // 28948022302589062190674361737351893382521535853822578548883407827216774463488


        /**
        * Point decompress NIST curve
        * @param {Uint8Array} Compressed representation
        * @return {Object} Explicit x & y
        */
        function ECPointDecompress( comp )
        {
        const signY = comp[0] - 2, // This value must be 2 or 3. 4 indicates an uncompressed key, and anything else is invalid.
        x = comp.subarray(1),
        // Import x into bigInt library
        xBig = new bigInt( x );

        // y^2 = x^3 - 3x + b
        var yBig = xBig.pow(3).sub( xBig.multiply(3) ).add( b ).modPow( pIdent, prime );

        // If the parity doesn't match it's the *other* root
        if( yBig.mod(2) !== signY )
        {
        // y = prime - y
        yBig = prime.sub( yBig );
        }

        return {
        x: x,
        y: yBig.toUint8Array()
        };
        }





        share|improve this answer





















        • 1





          note that sub method has changed to subtract

          – Nicolas Del Valle
          Jul 1 '16 at 2:46













        • This is an excellent response which has not been sufficiently valued. @Adria, thank you!

          – denis bider
          May 11 '17 at 13:29
















        5














        I imagine they'll be increased interest in a JavaScript elliptic curve point compression solution, with WebCrypto support filtering into browsers.

        I'll use the NIST curves as the example, because these the ones I had to deal with when importing a compressed public key into WebCrypto.



        Curves and their primes
        NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1
        NIST P-384 (secp384r1) 2^384 - 2^128 - 2^96 + 2^32 - 1
        NIST P-521 (secp521r1) 2^521 - 1


        These prime numbers all satisfy the equation, p mod 4 === 3

        What this means is you can skip the somewhat complex general purpose Tonelli-Shanks algorithm, and use a simple identity to find the square roots.



        First, the compression part of 'point compression' is very simple. Record the sign of Y, then discard the value of Y.



        /**
        * Point compress elliptic curve key
        * @param {Uint8Array} x component
        * @param {Uint8Array} y component
        * @return {Uint8Array} Compressed representation
        */
        function ECPointCompress( x, y )
        {
        const out = new Uint8Array( x.length + 1 );

        out[0] = 2 + ( y[ y.length-1 ] & 1 );
        out.set( x, 1 );

        return out;
        }


        Decompression involves looking up the square root, then correcting depending on the Y parity bit.
        This function depends on a JavaScript big integer library which exposes the following functions: add, sub, multiply, pow, modPow.



        // Consts for P256 curve. Adjust accordingly
        const two = new bigInt(2),
        // 115792089210356248762697446949407573530086143415290314195533631308867097853951
        prime = two.pow(256).sub( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).sub(1),
        b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
        // Pre-computed value, or literal
        pIdent = prime.add(1).divide(4); // 28948022302589062190674361737351893382521535853822578548883407827216774463488


        /**
        * Point decompress NIST curve
        * @param {Uint8Array} Compressed representation
        * @return {Object} Explicit x & y
        */
        function ECPointDecompress( comp )
        {
        const signY = comp[0] - 2, // This value must be 2 or 3. 4 indicates an uncompressed key, and anything else is invalid.
        x = comp.subarray(1),
        // Import x into bigInt library
        xBig = new bigInt( x );

        // y^2 = x^3 - 3x + b
        var yBig = xBig.pow(3).sub( xBig.multiply(3) ).add( b ).modPow( pIdent, prime );

        // If the parity doesn't match it's the *other* root
        if( yBig.mod(2) !== signY )
        {
        // y = prime - y
        yBig = prime.sub( yBig );
        }

        return {
        x: x,
        y: yBig.toUint8Array()
        };
        }





        share|improve this answer





















        • 1





          note that sub method has changed to subtract

          – Nicolas Del Valle
          Jul 1 '16 at 2:46













        • This is an excellent response which has not been sufficiently valued. @Adria, thank you!

          – denis bider
          May 11 '17 at 13:29














        5












        5








        5







        I imagine they'll be increased interest in a JavaScript elliptic curve point compression solution, with WebCrypto support filtering into browsers.

        I'll use the NIST curves as the example, because these the ones I had to deal with when importing a compressed public key into WebCrypto.



        Curves and their primes
        NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1
        NIST P-384 (secp384r1) 2^384 - 2^128 - 2^96 + 2^32 - 1
        NIST P-521 (secp521r1) 2^521 - 1


        These prime numbers all satisfy the equation, p mod 4 === 3

        What this means is you can skip the somewhat complex general purpose Tonelli-Shanks algorithm, and use a simple identity to find the square roots.



        First, the compression part of 'point compression' is very simple. Record the sign of Y, then discard the value of Y.



        /**
        * Point compress elliptic curve key
        * @param {Uint8Array} x component
        * @param {Uint8Array} y component
        * @return {Uint8Array} Compressed representation
        */
        function ECPointCompress( x, y )
        {
        const out = new Uint8Array( x.length + 1 );

        out[0] = 2 + ( y[ y.length-1 ] & 1 );
        out.set( x, 1 );

        return out;
        }


        Decompression involves looking up the square root, then correcting depending on the Y parity bit.
        This function depends on a JavaScript big integer library which exposes the following functions: add, sub, multiply, pow, modPow.



        // Consts for P256 curve. Adjust accordingly
        const two = new bigInt(2),
        // 115792089210356248762697446949407573530086143415290314195533631308867097853951
        prime = two.pow(256).sub( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).sub(1),
        b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
        // Pre-computed value, or literal
        pIdent = prime.add(1).divide(4); // 28948022302589062190674361737351893382521535853822578548883407827216774463488


        /**
        * Point decompress NIST curve
        * @param {Uint8Array} Compressed representation
        * @return {Object} Explicit x & y
        */
        function ECPointDecompress( comp )
        {
        const signY = comp[0] - 2, // This value must be 2 or 3. 4 indicates an uncompressed key, and anything else is invalid.
        x = comp.subarray(1),
        // Import x into bigInt library
        xBig = new bigInt( x );

        // y^2 = x^3 - 3x + b
        var yBig = xBig.pow(3).sub( xBig.multiply(3) ).add( b ).modPow( pIdent, prime );

        // If the parity doesn't match it's the *other* root
        if( yBig.mod(2) !== signY )
        {
        // y = prime - y
        yBig = prime.sub( yBig );
        }

        return {
        x: x,
        y: yBig.toUint8Array()
        };
        }





        share|improve this answer















        I imagine they'll be increased interest in a JavaScript elliptic curve point compression solution, with WebCrypto support filtering into browsers.

        I'll use the NIST curves as the example, because these the ones I had to deal with when importing a compressed public key into WebCrypto.



        Curves and their primes
        NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1
        NIST P-384 (secp384r1) 2^384 - 2^128 - 2^96 + 2^32 - 1
        NIST P-521 (secp521r1) 2^521 - 1


        These prime numbers all satisfy the equation, p mod 4 === 3

        What this means is you can skip the somewhat complex general purpose Tonelli-Shanks algorithm, and use a simple identity to find the square roots.



        First, the compression part of 'point compression' is very simple. Record the sign of Y, then discard the value of Y.



        /**
        * Point compress elliptic curve key
        * @param {Uint8Array} x component
        * @param {Uint8Array} y component
        * @return {Uint8Array} Compressed representation
        */
        function ECPointCompress( x, y )
        {
        const out = new Uint8Array( x.length + 1 );

        out[0] = 2 + ( y[ y.length-1 ] & 1 );
        out.set( x, 1 );

        return out;
        }


        Decompression involves looking up the square root, then correcting depending on the Y parity bit.
        This function depends on a JavaScript big integer library which exposes the following functions: add, sub, multiply, pow, modPow.



        // Consts for P256 curve. Adjust accordingly
        const two = new bigInt(2),
        // 115792089210356248762697446949407573530086143415290314195533631308867097853951
        prime = two.pow(256).sub( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).sub(1),
        b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
        // Pre-computed value, or literal
        pIdent = prime.add(1).divide(4); // 28948022302589062190674361737351893382521535853822578548883407827216774463488


        /**
        * Point decompress NIST curve
        * @param {Uint8Array} Compressed representation
        * @return {Object} Explicit x & y
        */
        function ECPointDecompress( comp )
        {
        const signY = comp[0] - 2, // This value must be 2 or 3. 4 indicates an uncompressed key, and anything else is invalid.
        x = comp.subarray(1),
        // Import x into bigInt library
        xBig = new bigInt( x );

        // y^2 = x^3 - 3x + b
        var yBig = xBig.pow(3).sub( xBig.multiply(3) ).add( b ).modPow( pIdent, prime );

        // If the parity doesn't match it's the *other* root
        if( yBig.mod(2) !== signY )
        {
        // y = prime - y
        yBig = prime.sub( yBig );
        }

        return {
        x: x,
        y: yBig.toUint8Array()
        };
        }






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited May 25 '15 at 5:13

























        answered May 25 '15 at 5:06









        AdriaAdria

        4,89032823




        4,89032823








        • 1





          note that sub method has changed to subtract

          – Nicolas Del Valle
          Jul 1 '16 at 2:46













        • This is an excellent response which has not been sufficiently valued. @Adria, thank you!

          – denis bider
          May 11 '17 at 13:29














        • 1





          note that sub method has changed to subtract

          – Nicolas Del Valle
          Jul 1 '16 at 2:46













        • This is an excellent response which has not been sufficiently valued. @Adria, thank you!

          – denis bider
          May 11 '17 at 13:29








        1




        1





        note that sub method has changed to subtract

        – Nicolas Del Valle
        Jul 1 '16 at 2:46







        note that sub method has changed to subtract

        – Nicolas Del Valle
        Jul 1 '16 at 2:46















        This is an excellent response which has not been sufficiently valued. @Adria, thank you!

        – denis bider
        May 11 '17 at 13:29





        This is an excellent response which has not been sufficiently valued. @Adria, thank you!

        – denis bider
        May 11 '17 at 13:29













        0














        It would be difficult to patent a methematical formula alone. The use of a quadratic equation y = sqrt(x^3+ax+b) can't be patented, and if it is, cannot be protected. One can certainly claim prior art from Diophantes (200-298 AD). and the work around Hall conjecture (circa 1971) about the smallest absolute difference betwwen a square and a cube |y^2 - x^3| being rarely less than x. Rewrite it y^2 - x^3 = ax-b with x < b/a and remark that solutions in modular groups would help reduce the amount of brute force search in integers.



        What is patented is the bit which helps to figure out the sign of y. This bit can be used to discriminate the largest of the solution from (y and M-y), or the positive solution from (y, -y), depending the standards you look at.



        But since the patent has been accepted, you need to seek a legal advice.



        As a reputable cryptographer well versed in the skills of the art Dr. Dan Bernstein points judiciously ( http://cr.yp.to/ecdh/patents.html ), the idea of recomputing y from x is mentioned in Miller 1986 as a triviality to reduce the footprint of elliptic curves points in memory-based systems.



        A lawyer specialized in patent claims could help you to assess if the patent still applies if you do not use a normal basis as a representation of the point coordinates, or in the case of ecc in gf(p), or if you do not use a bit to recode the compressed value of y, e.g. when choosing the randomness k, P1(x1,y1) and computing P2(x2,y2) = [k]P1 until tr(y1) == tr(y2) removes the ambiguity (a little bit CPU costly, but why not ?).



        Alternatively, you can point that the resolution of the quadratic formula is evidently more costly than the few bits saved on a communication channels and this patent is not useful at all, and even damaging for the environment by suggesting the replacement of 6 picowatts of transmission costs by 2 miliwatts of CPU costs (To be acceptable, a patent submission must be new, non-trivial and useful). Then you find a crooked lawyer preferably in California and for sure, there will be a local judge to award you a few $billions for the damages caused to the environment, for the distress caused to your programming skills and to your wallet considering the resulting delays in the release of your valuable application.



        Else, as suggested in another post, you go for a licensing solution.



        If your application is for the US government, you need another lawyer to assess if this patent and the way you plan to use it is already part of the licences purchased by NSA in the context of the "Suite B" of algorithms, in which case the license could already be payed for by the people of the US.






        share|improve this answer






























          0














          It would be difficult to patent a methematical formula alone. The use of a quadratic equation y = sqrt(x^3+ax+b) can't be patented, and if it is, cannot be protected. One can certainly claim prior art from Diophantes (200-298 AD). and the work around Hall conjecture (circa 1971) about the smallest absolute difference betwwen a square and a cube |y^2 - x^3| being rarely less than x. Rewrite it y^2 - x^3 = ax-b with x < b/a and remark that solutions in modular groups would help reduce the amount of brute force search in integers.



          What is patented is the bit which helps to figure out the sign of y. This bit can be used to discriminate the largest of the solution from (y and M-y), or the positive solution from (y, -y), depending the standards you look at.



          But since the patent has been accepted, you need to seek a legal advice.



          As a reputable cryptographer well versed in the skills of the art Dr. Dan Bernstein points judiciously ( http://cr.yp.to/ecdh/patents.html ), the idea of recomputing y from x is mentioned in Miller 1986 as a triviality to reduce the footprint of elliptic curves points in memory-based systems.



          A lawyer specialized in patent claims could help you to assess if the patent still applies if you do not use a normal basis as a representation of the point coordinates, or in the case of ecc in gf(p), or if you do not use a bit to recode the compressed value of y, e.g. when choosing the randomness k, P1(x1,y1) and computing P2(x2,y2) = [k]P1 until tr(y1) == tr(y2) removes the ambiguity (a little bit CPU costly, but why not ?).



          Alternatively, you can point that the resolution of the quadratic formula is evidently more costly than the few bits saved on a communication channels and this patent is not useful at all, and even damaging for the environment by suggesting the replacement of 6 picowatts of transmission costs by 2 miliwatts of CPU costs (To be acceptable, a patent submission must be new, non-trivial and useful). Then you find a crooked lawyer preferably in California and for sure, there will be a local judge to award you a few $billions for the damages caused to the environment, for the distress caused to your programming skills and to your wallet considering the resulting delays in the release of your valuable application.



          Else, as suggested in another post, you go for a licensing solution.



          If your application is for the US government, you need another lawyer to assess if this patent and the way you plan to use it is already part of the licences purchased by NSA in the context of the "Suite B" of algorithms, in which case the license could already be payed for by the people of the US.






          share|improve this answer




























            0












            0








            0







            It would be difficult to patent a methematical formula alone. The use of a quadratic equation y = sqrt(x^3+ax+b) can't be patented, and if it is, cannot be protected. One can certainly claim prior art from Diophantes (200-298 AD). and the work around Hall conjecture (circa 1971) about the smallest absolute difference betwwen a square and a cube |y^2 - x^3| being rarely less than x. Rewrite it y^2 - x^3 = ax-b with x < b/a and remark that solutions in modular groups would help reduce the amount of brute force search in integers.



            What is patented is the bit which helps to figure out the sign of y. This bit can be used to discriminate the largest of the solution from (y and M-y), or the positive solution from (y, -y), depending the standards you look at.



            But since the patent has been accepted, you need to seek a legal advice.



            As a reputable cryptographer well versed in the skills of the art Dr. Dan Bernstein points judiciously ( http://cr.yp.to/ecdh/patents.html ), the idea of recomputing y from x is mentioned in Miller 1986 as a triviality to reduce the footprint of elliptic curves points in memory-based systems.



            A lawyer specialized in patent claims could help you to assess if the patent still applies if you do not use a normal basis as a representation of the point coordinates, or in the case of ecc in gf(p), or if you do not use a bit to recode the compressed value of y, e.g. when choosing the randomness k, P1(x1,y1) and computing P2(x2,y2) = [k]P1 until tr(y1) == tr(y2) removes the ambiguity (a little bit CPU costly, but why not ?).



            Alternatively, you can point that the resolution of the quadratic formula is evidently more costly than the few bits saved on a communication channels and this patent is not useful at all, and even damaging for the environment by suggesting the replacement of 6 picowatts of transmission costs by 2 miliwatts of CPU costs (To be acceptable, a patent submission must be new, non-trivial and useful). Then you find a crooked lawyer preferably in California and for sure, there will be a local judge to award you a few $billions for the damages caused to the environment, for the distress caused to your programming skills and to your wallet considering the resulting delays in the release of your valuable application.



            Else, as suggested in another post, you go for a licensing solution.



            If your application is for the US government, you need another lawyer to assess if this patent and the way you plan to use it is already part of the licences purchased by NSA in the context of the "Suite B" of algorithms, in which case the license could already be payed for by the people of the US.






            share|improve this answer















            It would be difficult to patent a methematical formula alone. The use of a quadratic equation y = sqrt(x^3+ax+b) can't be patented, and if it is, cannot be protected. One can certainly claim prior art from Diophantes (200-298 AD). and the work around Hall conjecture (circa 1971) about the smallest absolute difference betwwen a square and a cube |y^2 - x^3| being rarely less than x. Rewrite it y^2 - x^3 = ax-b with x < b/a and remark that solutions in modular groups would help reduce the amount of brute force search in integers.



            What is patented is the bit which helps to figure out the sign of y. This bit can be used to discriminate the largest of the solution from (y and M-y), or the positive solution from (y, -y), depending the standards you look at.



            But since the patent has been accepted, you need to seek a legal advice.



            As a reputable cryptographer well versed in the skills of the art Dr. Dan Bernstein points judiciously ( http://cr.yp.to/ecdh/patents.html ), the idea of recomputing y from x is mentioned in Miller 1986 as a triviality to reduce the footprint of elliptic curves points in memory-based systems.



            A lawyer specialized in patent claims could help you to assess if the patent still applies if you do not use a normal basis as a representation of the point coordinates, or in the case of ecc in gf(p), or if you do not use a bit to recode the compressed value of y, e.g. when choosing the randomness k, P1(x1,y1) and computing P2(x2,y2) = [k]P1 until tr(y1) == tr(y2) removes the ambiguity (a little bit CPU costly, but why not ?).



            Alternatively, you can point that the resolution of the quadratic formula is evidently more costly than the few bits saved on a communication channels and this patent is not useful at all, and even damaging for the environment by suggesting the replacement of 6 picowatts of transmission costs by 2 miliwatts of CPU costs (To be acceptable, a patent submission must be new, non-trivial and useful). Then you find a crooked lawyer preferably in California and for sure, there will be a local judge to award you a few $billions for the damages caused to the environment, for the distress caused to your programming skills and to your wallet considering the resulting delays in the release of your valuable application.



            Else, as suggested in another post, you go for a licensing solution.



            If your application is for the US government, you need another lawyer to assess if this patent and the way you plan to use it is already part of the licences purchased by NSA in the context of the "Suite B" of algorithms, in which case the license could already be payed for by the people of the US.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Feb 22 '14 at 17:19









            Jay Kominek

            7,57512647




            7,57512647










            answered Dec 5 '13 at 3:39









            PierrePierre

            35714




            35714























                0














                Compression of elliptic curve points is patented by Certicom, so you should not use it without the license, generally.



                Update: Certicom's patent was expired in 2014, according to the comment by denis bider below.






                share|improve this answer


























                • I don't want to get into politics generally but which jurisdiction allows software patents ?

                  – Ian Purton
                  Jun 18 '13 at 14:45











                • Almost every, including USA. You can read more on ECC patents on en.wikipedia.org/wiki/ECC_patents

                  – Nickolay Olshevsky
                  Jun 18 '13 at 14:46











                • Perhaps the USA, but nto the Eu. en.wikipedia.org/wiki/Software_patent In Europe, "computer programs as such" are excluded from patentability and European Patent Office policy is consequently that a program for a computer is not patentable if it does not have the potential to cause a "further technical effect" beyond the inherent technical interactions between hardware and software.

                  – Ian Purton
                  Jun 18 '13 at 14:50













                • Actually patented not the computer program, but mathematic method. Anyway, I'm not a specialist in European/USA patent laws, just wanted to warn you. In most interent standards compressed points are not supported just because of that stupid patent.

                  – Nickolay Olshevsky
                  Jun 18 '13 at 15:08











                • Thanks, I appreciate the heads up.

                  – Ian Purton
                  Jun 20 '13 at 6:09
















                0














                Compression of elliptic curve points is patented by Certicom, so you should not use it without the license, generally.



                Update: Certicom's patent was expired in 2014, according to the comment by denis bider below.






                share|improve this answer


























                • I don't want to get into politics generally but which jurisdiction allows software patents ?

                  – Ian Purton
                  Jun 18 '13 at 14:45











                • Almost every, including USA. You can read more on ECC patents on en.wikipedia.org/wiki/ECC_patents

                  – Nickolay Olshevsky
                  Jun 18 '13 at 14:46











                • Perhaps the USA, but nto the Eu. en.wikipedia.org/wiki/Software_patent In Europe, "computer programs as such" are excluded from patentability and European Patent Office policy is consequently that a program for a computer is not patentable if it does not have the potential to cause a "further technical effect" beyond the inherent technical interactions between hardware and software.

                  – Ian Purton
                  Jun 18 '13 at 14:50













                • Actually patented not the computer program, but mathematic method. Anyway, I'm not a specialist in European/USA patent laws, just wanted to warn you. In most interent standards compressed points are not supported just because of that stupid patent.

                  – Nickolay Olshevsky
                  Jun 18 '13 at 15:08











                • Thanks, I appreciate the heads up.

                  – Ian Purton
                  Jun 20 '13 at 6:09














                0












                0








                0







                Compression of elliptic curve points is patented by Certicom, so you should not use it without the license, generally.



                Update: Certicom's patent was expired in 2014, according to the comment by denis bider below.






                share|improve this answer















                Compression of elliptic curve points is patented by Certicom, so you should not use it without the license, generally.



                Update: Certicom's patent was expired in 2014, according to the comment by denis bider below.







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited May 12 '17 at 12:26

























                answered Jun 18 '13 at 14:39









                Nickolay OlshevskyNickolay Olshevsky

                11.3k12138




                11.3k12138













                • I don't want to get into politics generally but which jurisdiction allows software patents ?

                  – Ian Purton
                  Jun 18 '13 at 14:45











                • Almost every, including USA. You can read more on ECC patents on en.wikipedia.org/wiki/ECC_patents

                  – Nickolay Olshevsky
                  Jun 18 '13 at 14:46











                • Perhaps the USA, but nto the Eu. en.wikipedia.org/wiki/Software_patent In Europe, "computer programs as such" are excluded from patentability and European Patent Office policy is consequently that a program for a computer is not patentable if it does not have the potential to cause a "further technical effect" beyond the inherent technical interactions between hardware and software.

                  – Ian Purton
                  Jun 18 '13 at 14:50













                • Actually patented not the computer program, but mathematic method. Anyway, I'm not a specialist in European/USA patent laws, just wanted to warn you. In most interent standards compressed points are not supported just because of that stupid patent.

                  – Nickolay Olshevsky
                  Jun 18 '13 at 15:08











                • Thanks, I appreciate the heads up.

                  – Ian Purton
                  Jun 20 '13 at 6:09



















                • I don't want to get into politics generally but which jurisdiction allows software patents ?

                  – Ian Purton
                  Jun 18 '13 at 14:45











                • Almost every, including USA. You can read more on ECC patents on en.wikipedia.org/wiki/ECC_patents

                  – Nickolay Olshevsky
                  Jun 18 '13 at 14:46











                • Perhaps the USA, but nto the Eu. en.wikipedia.org/wiki/Software_patent In Europe, "computer programs as such" are excluded from patentability and European Patent Office policy is consequently that a program for a computer is not patentable if it does not have the potential to cause a "further technical effect" beyond the inherent technical interactions between hardware and software.

                  – Ian Purton
                  Jun 18 '13 at 14:50













                • Actually patented not the computer program, but mathematic method. Anyway, I'm not a specialist in European/USA patent laws, just wanted to warn you. In most interent standards compressed points are not supported just because of that stupid patent.

                  – Nickolay Olshevsky
                  Jun 18 '13 at 15:08











                • Thanks, I appreciate the heads up.

                  – Ian Purton
                  Jun 20 '13 at 6:09

















                I don't want to get into politics generally but which jurisdiction allows software patents ?

                – Ian Purton
                Jun 18 '13 at 14:45





                I don't want to get into politics generally but which jurisdiction allows software patents ?

                – Ian Purton
                Jun 18 '13 at 14:45













                Almost every, including USA. You can read more on ECC patents on en.wikipedia.org/wiki/ECC_patents

                – Nickolay Olshevsky
                Jun 18 '13 at 14:46





                Almost every, including USA. You can read more on ECC patents on en.wikipedia.org/wiki/ECC_patents

                – Nickolay Olshevsky
                Jun 18 '13 at 14:46













                Perhaps the USA, but nto the Eu. en.wikipedia.org/wiki/Software_patent In Europe, "computer programs as such" are excluded from patentability and European Patent Office policy is consequently that a program for a computer is not patentable if it does not have the potential to cause a "further technical effect" beyond the inherent technical interactions between hardware and software.

                – Ian Purton
                Jun 18 '13 at 14:50







                Perhaps the USA, but nto the Eu. en.wikipedia.org/wiki/Software_patent In Europe, "computer programs as such" are excluded from patentability and European Patent Office policy is consequently that a program for a computer is not patentable if it does not have the potential to cause a "further technical effect" beyond the inherent technical interactions between hardware and software.

                – Ian Purton
                Jun 18 '13 at 14:50















                Actually patented not the computer program, but mathematic method. Anyway, I'm not a specialist in European/USA patent laws, just wanted to warn you. In most interent standards compressed points are not supported just because of that stupid patent.

                – Nickolay Olshevsky
                Jun 18 '13 at 15:08





                Actually patented not the computer program, but mathematic method. Anyway, I'm not a specialist in European/USA patent laws, just wanted to warn you. In most interent standards compressed points are not supported just because of that stupid patent.

                – Nickolay Olshevsky
                Jun 18 '13 at 15:08













                Thanks, I appreciate the heads up.

                – Ian Purton
                Jun 20 '13 at 6:09





                Thanks, I appreciate the heads up.

                – Ian Purton
                Jun 20 '13 at 6:09











                0














                Code for converting bitcoin compressed public key (ECDSA public key) to an 65 bytes of an uncompressed public key, using secp256k1 curve consts, with javascript big integer library latest version 1.6.36, and it can work with hex string directly



                const bigInt = require("big-integer");

                function pad_with_zeroes(number, length) {
                var retval = '' + number;
                while (retval.length < length) {
                retval = '0' + retval;
                }
                return retval;
                }

                // Consts for secp256k1 curve. Adjust accordingly
                // https://en.bitcoin.it/wiki/Secp256k1
                const prime = new bigInt('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16),
                pIdent = prime.add(1).divide(4);

                /**
                * Point decompress secp256k1 curve
                * @param {string} Compressed representation in hex string
                * @return {string} Uncompressed representation in hex string
                */
                function ECPointDecompress( comp ) {
                var signY = new Number(comp[1]) - 2;
                var x = new bigInt(comp.substring(2), 16);
                // y mod p = +-(x^3 + 7)^((p+1)/4) mod p
                var y = x.modPow(3, prime).add(7).mod(prime).modPow( pIdent, prime );
                // If the parity doesn't match it's the *other* root
                if( y.mod(2).toJSNumber() !== signY ) {
                // y = prime - y
                y = prime.subtract( y );
                }
                return '04' + pad_with_zeroes(x.toString(16), 64) + pad_with_zeroes(y.toString(16), 64);
                }


                Example with private key: 55255657523dd1c65a77d3cb53fcd050bf7fc2c11bb0bb6edabdbd41ea51f641



                ECPointDecompress('0314fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267')


                returns: '0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf'






                share|improve this answer




























                  0














                  Code for converting bitcoin compressed public key (ECDSA public key) to an 65 bytes of an uncompressed public key, using secp256k1 curve consts, with javascript big integer library latest version 1.6.36, and it can work with hex string directly



                  const bigInt = require("big-integer");

                  function pad_with_zeroes(number, length) {
                  var retval = '' + number;
                  while (retval.length < length) {
                  retval = '0' + retval;
                  }
                  return retval;
                  }

                  // Consts for secp256k1 curve. Adjust accordingly
                  // https://en.bitcoin.it/wiki/Secp256k1
                  const prime = new bigInt('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16),
                  pIdent = prime.add(1).divide(4);

                  /**
                  * Point decompress secp256k1 curve
                  * @param {string} Compressed representation in hex string
                  * @return {string} Uncompressed representation in hex string
                  */
                  function ECPointDecompress( comp ) {
                  var signY = new Number(comp[1]) - 2;
                  var x = new bigInt(comp.substring(2), 16);
                  // y mod p = +-(x^3 + 7)^((p+1)/4) mod p
                  var y = x.modPow(3, prime).add(7).mod(prime).modPow( pIdent, prime );
                  // If the parity doesn't match it's the *other* root
                  if( y.mod(2).toJSNumber() !== signY ) {
                  // y = prime - y
                  y = prime.subtract( y );
                  }
                  return '04' + pad_with_zeroes(x.toString(16), 64) + pad_with_zeroes(y.toString(16), 64);
                  }


                  Example with private key: 55255657523dd1c65a77d3cb53fcd050bf7fc2c11bb0bb6edabdbd41ea51f641



                  ECPointDecompress('0314fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267')


                  returns: '0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf'






                  share|improve this answer


























                    0












                    0








                    0







                    Code for converting bitcoin compressed public key (ECDSA public key) to an 65 bytes of an uncompressed public key, using secp256k1 curve consts, with javascript big integer library latest version 1.6.36, and it can work with hex string directly



                    const bigInt = require("big-integer");

                    function pad_with_zeroes(number, length) {
                    var retval = '' + number;
                    while (retval.length < length) {
                    retval = '0' + retval;
                    }
                    return retval;
                    }

                    // Consts for secp256k1 curve. Adjust accordingly
                    // https://en.bitcoin.it/wiki/Secp256k1
                    const prime = new bigInt('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16),
                    pIdent = prime.add(1).divide(4);

                    /**
                    * Point decompress secp256k1 curve
                    * @param {string} Compressed representation in hex string
                    * @return {string} Uncompressed representation in hex string
                    */
                    function ECPointDecompress( comp ) {
                    var signY = new Number(comp[1]) - 2;
                    var x = new bigInt(comp.substring(2), 16);
                    // y mod p = +-(x^3 + 7)^((p+1)/4) mod p
                    var y = x.modPow(3, prime).add(7).mod(prime).modPow( pIdent, prime );
                    // If the parity doesn't match it's the *other* root
                    if( y.mod(2).toJSNumber() !== signY ) {
                    // y = prime - y
                    y = prime.subtract( y );
                    }
                    return '04' + pad_with_zeroes(x.toString(16), 64) + pad_with_zeroes(y.toString(16), 64);
                    }


                    Example with private key: 55255657523dd1c65a77d3cb53fcd050bf7fc2c11bb0bb6edabdbd41ea51f641



                    ECPointDecompress('0314fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267')


                    returns: '0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf'






                    share|improve this answer













                    Code for converting bitcoin compressed public key (ECDSA public key) to an 65 bytes of an uncompressed public key, using secp256k1 curve consts, with javascript big integer library latest version 1.6.36, and it can work with hex string directly



                    const bigInt = require("big-integer");

                    function pad_with_zeroes(number, length) {
                    var retval = '' + number;
                    while (retval.length < length) {
                    retval = '0' + retval;
                    }
                    return retval;
                    }

                    // Consts for secp256k1 curve. Adjust accordingly
                    // https://en.bitcoin.it/wiki/Secp256k1
                    const prime = new bigInt('fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16),
                    pIdent = prime.add(1).divide(4);

                    /**
                    * Point decompress secp256k1 curve
                    * @param {string} Compressed representation in hex string
                    * @return {string} Uncompressed representation in hex string
                    */
                    function ECPointDecompress( comp ) {
                    var signY = new Number(comp[1]) - 2;
                    var x = new bigInt(comp.substring(2), 16);
                    // y mod p = +-(x^3 + 7)^((p+1)/4) mod p
                    var y = x.modPow(3, prime).add(7).mod(prime).modPow( pIdent, prime );
                    // If the parity doesn't match it's the *other* root
                    if( y.mod(2).toJSNumber() !== signY ) {
                    // y = prime - y
                    y = prime.subtract( y );
                    }
                    return '04' + pad_with_zeroes(x.toString(16), 64) + pad_with_zeroes(y.toString(16), 64);
                    }


                    Example with private key: 55255657523dd1c65a77d3cb53fcd050bf7fc2c11bb0bb6edabdbd41ea51f641



                    ECPointDecompress('0314fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267')


                    returns: '0414fc03b8df87cd7b872996810db8458d61da8448e531569c8517b469a119d267be5645686309c6e6736dbd93940707cc9143d3cf29f1b877ff340e2cb2d259cf'







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Nov 26 '18 at 11:30









                    chutiumchutium

                    23927




                    23927























                        0














                        code for ECPointDecompress above from @Adria is unfortunately outdated, it is using a very old version of JavaScript big integer library



                        I rewrite ECPointDecompress with big integer library latest version 1.6.36, and it can work with hex string directly, do not need to use Uint8Array:



                        const bigInt = require("big-integer");

                        // Consts for P256 curve. Adjust accordingly
                        const two = new bigInt(2),
                        // 115792089210356248762697446949407573530086143415290314195533631308867097853951
                        prime = two.pow(256).subtract( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).subtract(1),
                        b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
                        // Pre-computed value, or literal
                        // 28948022302589062190674361737351893382521535853822578548883407827216774463488
                        pIdent = prime.add(1).divide(4);

                        function pad_with_zeroes(number, length) {
                        var retval = '' + number;
                        while (retval.length < length) {
                        retval = '0' + retval;
                        }
                        return retval;
                        }

                        /**
                        * Point decompress NIST curve
                        * @param {string} Compressed representation in hex string
                        * @return {string} Uncompressed representation in hex string
                        */
                        function ECPointDecompress( comp ) {
                        var signY = new Number(comp[1]) - 2;
                        var x = new bigInt(comp.substring(2), 16);
                        // y^2 = x^3 - 3x + b
                        var y = x.pow(3).subtract( x.multiply(3) ).add( b ).modPow( pIdent, prime );
                        // If the parity doesn't match it's the *other* root
                        if( y.mod(2).toJSNumber() !== signY ) {
                        // y = prime - y
                        y = prime.subtract( y );
                        }
                        return '04' + pad_with_zeroes(x.toString(16), 64) + pad_with_zeroes(y.toString(16), 64);
                        }


                        This can be used to convert compressed public key (ECDSA public key) to an 65 bytes of an uncompressed public key, but note that bitcoin's compressed public key is created using secp256k1 curve, which is different to the curve that we used in this code: NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1



                        Therefore, above code can not be used to convert bitcoin's compressed public key, looking for converter of bitcoin compressed public key with secp256k1 curve consts, refer to https://stackoverflow.com/a/53480175/5630352



                        Examples:



                        ECPointDecompress('030ce2995c738e2320a5dea2df51b99d88bc5dd38356ba72e51ecc0ca660ca4593')


                        returns: '040ce2995c738e2320a5dea2df51b99d88bc5dd38356ba72e51ecc0ca660ca45936215a67f6e3fa1d72f6ef46aa2b7481991427b8764ff90447c6215d8dc931773'



                        ECPointDecompress('0267bc6cae41a4579cda2556818bc942a38321cad961028bc74459f36ddca71e0e')


                        returns: '0467bc6cae41a4579cda2556818bc942a38321cad961028bc74459f36ddca71e0e7c52f0e9f82bd1b2ba81935ba125cb1030d1ade1bd0306b3579a951418b858e8'






                        share|improve this answer






























                          0














                          code for ECPointDecompress above from @Adria is unfortunately outdated, it is using a very old version of JavaScript big integer library



                          I rewrite ECPointDecompress with big integer library latest version 1.6.36, and it can work with hex string directly, do not need to use Uint8Array:



                          const bigInt = require("big-integer");

                          // Consts for P256 curve. Adjust accordingly
                          const two = new bigInt(2),
                          // 115792089210356248762697446949407573530086143415290314195533631308867097853951
                          prime = two.pow(256).subtract( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).subtract(1),
                          b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
                          // Pre-computed value, or literal
                          // 28948022302589062190674361737351893382521535853822578548883407827216774463488
                          pIdent = prime.add(1).divide(4);

                          function pad_with_zeroes(number, length) {
                          var retval = '' + number;
                          while (retval.length < length) {
                          retval = '0' + retval;
                          }
                          return retval;
                          }

                          /**
                          * Point decompress NIST curve
                          * @param {string} Compressed representation in hex string
                          * @return {string} Uncompressed representation in hex string
                          */
                          function ECPointDecompress( comp ) {
                          var signY = new Number(comp[1]) - 2;
                          var x = new bigInt(comp.substring(2), 16);
                          // y^2 = x^3 - 3x + b
                          var y = x.pow(3).subtract( x.multiply(3) ).add( b ).modPow( pIdent, prime );
                          // If the parity doesn't match it's the *other* root
                          if( y.mod(2).toJSNumber() !== signY ) {
                          // y = prime - y
                          y = prime.subtract( y );
                          }
                          return '04' + pad_with_zeroes(x.toString(16), 64) + pad_with_zeroes(y.toString(16), 64);
                          }


                          This can be used to convert compressed public key (ECDSA public key) to an 65 bytes of an uncompressed public key, but note that bitcoin's compressed public key is created using secp256k1 curve, which is different to the curve that we used in this code: NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1



                          Therefore, above code can not be used to convert bitcoin's compressed public key, looking for converter of bitcoin compressed public key with secp256k1 curve consts, refer to https://stackoverflow.com/a/53480175/5630352



                          Examples:



                          ECPointDecompress('030ce2995c738e2320a5dea2df51b99d88bc5dd38356ba72e51ecc0ca660ca4593')


                          returns: '040ce2995c738e2320a5dea2df51b99d88bc5dd38356ba72e51ecc0ca660ca45936215a67f6e3fa1d72f6ef46aa2b7481991427b8764ff90447c6215d8dc931773'



                          ECPointDecompress('0267bc6cae41a4579cda2556818bc942a38321cad961028bc74459f36ddca71e0e')


                          returns: '0467bc6cae41a4579cda2556818bc942a38321cad961028bc74459f36ddca71e0e7c52f0e9f82bd1b2ba81935ba125cb1030d1ade1bd0306b3579a951418b858e8'






                          share|improve this answer




























                            0












                            0








                            0







                            code for ECPointDecompress above from @Adria is unfortunately outdated, it is using a very old version of JavaScript big integer library



                            I rewrite ECPointDecompress with big integer library latest version 1.6.36, and it can work with hex string directly, do not need to use Uint8Array:



                            const bigInt = require("big-integer");

                            // Consts for P256 curve. Adjust accordingly
                            const two = new bigInt(2),
                            // 115792089210356248762697446949407573530086143415290314195533631308867097853951
                            prime = two.pow(256).subtract( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).subtract(1),
                            b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
                            // Pre-computed value, or literal
                            // 28948022302589062190674361737351893382521535853822578548883407827216774463488
                            pIdent = prime.add(1).divide(4);

                            function pad_with_zeroes(number, length) {
                            var retval = '' + number;
                            while (retval.length < length) {
                            retval = '0' + retval;
                            }
                            return retval;
                            }

                            /**
                            * Point decompress NIST curve
                            * @param {string} Compressed representation in hex string
                            * @return {string} Uncompressed representation in hex string
                            */
                            function ECPointDecompress( comp ) {
                            var signY = new Number(comp[1]) - 2;
                            var x = new bigInt(comp.substring(2), 16);
                            // y^2 = x^3 - 3x + b
                            var y = x.pow(3).subtract( x.multiply(3) ).add( b ).modPow( pIdent, prime );
                            // If the parity doesn't match it's the *other* root
                            if( y.mod(2).toJSNumber() !== signY ) {
                            // y = prime - y
                            y = prime.subtract( y );
                            }
                            return '04' + pad_with_zeroes(x.toString(16), 64) + pad_with_zeroes(y.toString(16), 64);
                            }


                            This can be used to convert compressed public key (ECDSA public key) to an 65 bytes of an uncompressed public key, but note that bitcoin's compressed public key is created using secp256k1 curve, which is different to the curve that we used in this code: NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1



                            Therefore, above code can not be used to convert bitcoin's compressed public key, looking for converter of bitcoin compressed public key with secp256k1 curve consts, refer to https://stackoverflow.com/a/53480175/5630352



                            Examples:



                            ECPointDecompress('030ce2995c738e2320a5dea2df51b99d88bc5dd38356ba72e51ecc0ca660ca4593')


                            returns: '040ce2995c738e2320a5dea2df51b99d88bc5dd38356ba72e51ecc0ca660ca45936215a67f6e3fa1d72f6ef46aa2b7481991427b8764ff90447c6215d8dc931773'



                            ECPointDecompress('0267bc6cae41a4579cda2556818bc942a38321cad961028bc74459f36ddca71e0e')


                            returns: '0467bc6cae41a4579cda2556818bc942a38321cad961028bc74459f36ddca71e0e7c52f0e9f82bd1b2ba81935ba125cb1030d1ade1bd0306b3579a951418b858e8'






                            share|improve this answer















                            code for ECPointDecompress above from @Adria is unfortunately outdated, it is using a very old version of JavaScript big integer library



                            I rewrite ECPointDecompress with big integer library latest version 1.6.36, and it can work with hex string directly, do not need to use Uint8Array:



                            const bigInt = require("big-integer");

                            // Consts for P256 curve. Adjust accordingly
                            const two = new bigInt(2),
                            // 115792089210356248762697446949407573530086143415290314195533631308867097853951
                            prime = two.pow(256).subtract( two.pow(224) ).add( two.pow(192) ).add( two.pow(96) ).subtract(1),
                            b = new bigInt( '41058363725152142129326129780047268409114441015993725554835256314039467401291' ),
                            // Pre-computed value, or literal
                            // 28948022302589062190674361737351893382521535853822578548883407827216774463488
                            pIdent = prime.add(1).divide(4);

                            function pad_with_zeroes(number, length) {
                            var retval = '' + number;
                            while (retval.length < length) {
                            retval = '0' + retval;
                            }
                            return retval;
                            }

                            /**
                            * Point decompress NIST curve
                            * @param {string} Compressed representation in hex string
                            * @return {string} Uncompressed representation in hex string
                            */
                            function ECPointDecompress( comp ) {
                            var signY = new Number(comp[1]) - 2;
                            var x = new bigInt(comp.substring(2), 16);
                            // y^2 = x^3 - 3x + b
                            var y = x.pow(3).subtract( x.multiply(3) ).add( b ).modPow( pIdent, prime );
                            // If the parity doesn't match it's the *other* root
                            if( y.mod(2).toJSNumber() !== signY ) {
                            // y = prime - y
                            y = prime.subtract( y );
                            }
                            return '04' + pad_with_zeroes(x.toString(16), 64) + pad_with_zeroes(y.toString(16), 64);
                            }


                            This can be used to convert compressed public key (ECDSA public key) to an 65 bytes of an uncompressed public key, but note that bitcoin's compressed public key is created using secp256k1 curve, which is different to the curve that we used in this code: NIST P-256 (secp256r1) 2^256 - 2^224 + 2^192 + 2^96 - 1



                            Therefore, above code can not be used to convert bitcoin's compressed public key, looking for converter of bitcoin compressed public key with secp256k1 curve consts, refer to https://stackoverflow.com/a/53480175/5630352



                            Examples:



                            ECPointDecompress('030ce2995c738e2320a5dea2df51b99d88bc5dd38356ba72e51ecc0ca660ca4593')


                            returns: '040ce2995c738e2320a5dea2df51b99d88bc5dd38356ba72e51ecc0ca660ca45936215a67f6e3fa1d72f6ef46aa2b7481991427b8764ff90447c6215d8dc931773'



                            ECPointDecompress('0267bc6cae41a4579cda2556818bc942a38321cad961028bc74459f36ddca71e0e')


                            returns: '0467bc6cae41a4579cda2556818bc942a38321cad961028bc74459f36ddca71e0e7c52f0e9f82bd1b2ba81935ba125cb1030d1ade1bd0306b3579a951418b858e8'







                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Nov 26 '18 at 11:41

























                            answered Nov 26 '18 at 9:39









                            chutiumchutium

                            23927




                            23927






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f17171542%2falgorithm-for-elliptic-curve-point-compression%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Costa Masnaga

                                Fotorealismo

                                Sidney Franklin