Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6375659
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 25, 20262026-05-25T01:38:40+00:00 2026-05-25T01:38:40+00:00

According to OpenID Authentication 2.0 , section 4.2, Arbitrary precision integers MUST be encoded

  • 0

According to OpenID Authentication 2.0, section 4.2,

Arbitrary precision integers MUST be encoded as big-endian signed two’s complement binary strings. Henceforth, "btwoc" is a function that takes an arbitrary precision integer and returns its shortest big-endian two’s complement representation. All integers that are used with Diffie-Hellman Key Exchange are positive. This means that the left-most bit of the two’s complement representation MUST be zero. If it is not, implementations MUST add a zero byte at the front of the string.

Non-normative example:

Base 10 number | btwoc string representation
---------------+----------------------------
0              | "\x00"
127            | "\x7F"
128            | "\x00\x80"
255            | "\x00\xFF"
32768          | "\x00\x80\x00"

I have tried writing my own implementation of btwoc in C, and this is what I have:

typedef struct {
    uint8_t *data;
    uintmax_t length;
} oid_data;

oid_data *oid_btwoc_r(uintmax_t value, oid_data *ret) {
    unsigned    fnz = sizeof(uintmax_t) + 1,
                i = sizeof(uintmax_t) * 8;
    while (--fnz && (!(value >> (i -= 8) & 0xFF)));
    /*
        If `value' is non-zero, `fnz' now contains the index of the first
        non-zero byte in `value', where 1 refers to the least-significant byte.
        `fnz' will therefore be in the range [1 .. sizeof(uintmax_t)]. If
        `value' is zero, then `fnz' is zero.
    */
    if (!value) {
        /* The value is zero */
        ret->length = 1;
        ret->data[0] = 0;
    } else if (value >> ((fnz - 1) * 8 + 7)) {
        /* The most significant bit of the first non-zero byte is 1 */
        ret->length = fnz + 1;
        ret->data[0] = 0;
        for (i = 1; i <= fnz; i++)
            ret->data[1 + fnz - i] =
                value >> ((i - 1) * 8);
    } else {
        /* The most significant bit of the first non-zero byte is 0 */
        ret->length = fnz;
        for (i = 1; i <= fnz; i++)
            ret->data[fnz - i] =
                value >> ((i - 1) * 8);
    }
    return ret;
}

ret->data should point to valid memory of at least sizeof(uintmax_t) + 1 bytes.

It works fine, and I haven’t discovered any bugs in the implementation yet, but can it be optimised?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-25T01:38:40+00:00Added an answer on May 25, 2026 at 1:38 am

    If you keep zero as a special case, you should surely deal with it before the while loop. (Personal bête noire: I dislike (!value) for (value == 0).)


    I’ve not tried timing this (yet), but this code produces the same answer as yours (at least on the values I tested; see below) and looks simpler to me, not least because it doesn’t double up the code to deal with the case where the high bit is set in the most significant byte:

    void oid_btwoc_r2(uintmax_t value, oid_data *ret)
    {
        if (value == 0)
        {
            ret->data[0] = 0;
            ret->length  = 1;
            return;
        }
    
        uintmax_t v0 = value;
        uintmax_t v1 = v0;
        unsigned  n  = 0;
    
        while (v0 != 0)
        {
            n++;
            v1 = v0;
            v0 >>= 8;
        }
        //printf("Value: 0x%" PRIXMAX ", v1 = 0x%" PRIXMAX "\n", value, v1);
    
        assert(v1 < 0x100 && v1 != 0);
        if (v1 > 0x7F)
            n++;
        //printf("N = %u\n", n);
    
        for (unsigned i = n; i != 0; i--)
        {
            ret->data[i-1] = (value & 0xFF);
            value >>= 8;
        }
        ret->length = n;
    }
    

    The code I used to test this against your version was:

    #include <assert.h>
    #include <inttypes.h>
    #include <stdio.h>
    #include <string.h>
    
    #define DIM(x)  (sizeof(x) / sizeof(*(x)))
    
    static void dump_oid_data(FILE *fp, const char *tag, const oid_data *data)
    {
        fprintf(fp, "%s: length %" PRIuMAX ":", tag, data->length);
        for (uintmax_t i = 0; i < data->length; i++)
            fprintf(fp, " 0x%02X", data->data[i]);
        fputc('\n', fp);
    }
    
    int main(void)
    {
        uintmax_t list[] = { 0, 0x7F, 0x80, 0xFF, 0x100, 0x7FFF, 0x8000, 0xFFFF,
                             0x10000, 0x7FFFFF, 0x800000, 0xFFFFFF };
    
        for (size_t i = 0; i < DIM(list); i++)
        {
            uint8_t b1[sizeof(uintmax_t) + 1];
            uint8_t b2[sizeof(uintmax_t) + 1];
            oid_data v1 = { b1, sizeof(b1) };
            oid_data v2 = { b2, sizeof(b2) };
            oid_btwoc_r(list[i], &v1);
            oid_btwoc_r2(list[i], &v2);
            printf("Value: 0x%" PRIXMAX ": ", list[i]);
            if (v1.length != v2.length)
                printf("Lengths differ (%" PRIuMAX " vs %" PRIuMAX ")\n", v1.length, v2.length);
            else if (memcmp(v1.data, v2.data, v1.length) != 0)
            {
                printf("Data differs!\n");
                dump_oid_data(stdout, "oid_btwoc_r1()", &v1);
                dump_oid_data(stdout, "oid_btwoc_r2()", &v2);
            }
            else
            {
                printf("Values are the same\n");
                dump_oid_data(stdout, "oid_btwoc_rN()", &v2);
            }
        }
        return(0);
    }
    

    Yes; an early version of the code needed the dump function to see what was going wrong!

    Timing

    I adapted the original oid_btwoc_r() to a function returning void (no final return) and renamed it oid_btwoc_r1(). I then ran a timing test (on a Mac Mini running MacOS X Lion 10.7.1), and got the timing results:

    oid_btwoc_r1(): 4.925386
    oid_btwoc_r2(): 4.022604
    oid_btwoc_r1(): 4.930649
    oid_btwoc_r2(): 4.004344
    oid_btwoc_r1(): 4.927602
    oid_btwoc_r2(): 4.005756
    oid_btwoc_r1(): 4.923356
    oid_btwoc_r2(): 4.007910
    oid_btwoc_r1(): 4.984037
    oid_btwoc_r2(): 4.202986
    oid_btwoc_r1(): 5.015747
    oid_btwoc_r2(): 4.067265
    oid_btwoc_r1(): 4.982333
    oid_btwoc_r2(): 4.019807
    oid_btwoc_r1(): 4.957866
    oid_btwoc_r2(): 4.074712
    oid_btwoc_r1(): 4.993991
    oid_btwoc_r2(): 4.042422
    oid_btwoc_r1(): 4.970930
    oid_btwoc_r2(): 4.077203
    

    Consequently, it appears that the oid_btwoc_r2() function is about 20% faster than the original – at least on the data tested. Bigger numbers alter the balance in favour of oid_btwoc_r(), with `oid_btwoc_r1() then being about 20% faster:

    oid_btwoc_r1(): 3.671201
    oid_btwoc_r2(): 4.605171
    oid_btwoc_r1(): 3.669026
    oid_btwoc_r2(): 4.575745
    oid_btwoc_r1(): 3.673729
    oid_btwoc_r2(): 4.659433
    oid_btwoc_r1(): 3.684662
    oid_btwoc_r2(): 4.671654
    oid_btwoc_r1(): 3.730757
    oid_btwoc_r2(): 4.645485
    oid_btwoc_r1(): 3.764600
    oid_btwoc_r2(): 4.673244
    oid_btwoc_r1(): 3.669582
    oid_btwoc_r2(): 4.610177
    oid_btwoc_r1(): 3.664248
    oid_btwoc_r2(): 4.813711
    oid_btwoc_r1(): 3.675927
    oid_btwoc_r2(): 4.630148
    oid_btwoc_r1(): 3.681798
    oid_btwoc_r2(): 4.614129
    

    Since big numbers are probably more likely than small ones in this context, oid_btwoc_r1() – or the original oid_btwoc_r() – is arguably the better choice.

    The test code follows. The uncommented for loop is the ‘large number’ version which shows oid_btwoc_r1() working faster than oid_btwoc_r2(); the commented out for loop is the ‘small number’ version which shows oid_btwoc_r2() working faster than oid_btowc_r1().

    static void test_converter(const char *tag, void (*function)(uintmax_t, oid_data *))
    {
        Clock clk;
        clk_init(&clk);
        clk_start(&clk);
        for (uintmax_t i = 0x100000000; i < 0x1000000000000000; i += 0x170000000)
        //for (uintmax_t i = 0; i < 0x100000000; i += 17)
        {
            uint8_t b1[sizeof(uintmax_t) + 1];
            oid_data v1 = { b1, sizeof(b1) };
            (*function)(i, &v1);
        }
        clk_stop(&clk);
        char buffer[32];
        printf("%s: %s\n", tag, clk_elapsed_us(&clk, buffer, sizeof(buffer)));
    }
    
    int main(void)
    {
        for (int i = 0; i < 10; i++)
        {
            test_converter("oid_btwoc_r1()", oid_btwoc_r1);
            test_converter("oid_btwoc_r2()", oid_btwoc_r2);
        }
        return(0);
    }
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

According to this discussion , the iphone agreement says that it doesn't allow loading
According to the manual , git dcommit will create a revision in SVN for
According to the documentation, they're pretty much interchangeable. Is there a stylistic reason to
According to MSDN form.RightToLeftLayout = True; form.RightToLeft = ifWeWantRTL() ? RightToLeft.True : RightToLeft.False; is
According to select name from system_privilege_map System has been granted: SELECT ANY TABLE ...and
According to what I have found so far, I can use the following code:
According to the answers to this question, I cannot embed a file version in
According to Wikipedia, on the Comparison of programming languages page, it says that F#
According to this article Silverlight 2 Beta 2 supports the DataContractJsonSerializer object. But, when
According to the feedparser documentation , I can turn an RSS feed into a

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.