API Use Example: Elliptic Curve

It turns out we probably don't need to be adding Curve25519 right at the moment for TLS. But how quick I could bridge to a short C implementation's function was really neat, so I thought I'd both save the code and show it off.

What happens is it takes a 32-byte input and an optional 32-byte basepoint, both as BINARY!. Then it returns another 32-byte result from calling the C implementation on the unsigned char* buffers (REBYTE):

//  export curve25519: native [
//      return: "32-byte binary of public key data"
//          [binary!]
//      secret "32-byte binary of secret data"
//          [binary!]
//      /basepoint "optional 32-bytes, defaults to #{09000000...}"
//          [binary!] 
//  ]

    size_t secret_size;
    REBYTE *secret = rebBytes(&secret_size,
        "if 32 != length of", ARG(secret), "[",
            "fail {SECRET must be a 32-byte BINARY! for curve25519}",
    assert(secret_size == 32);

    size_t basepoint_size;
    REBYTE *opt_basepoint = rebBytes(&basepoint_size,
        "if all [", REF(basepoint), "32 != length of", REF(basepoint), "] [",
            "fail {/BASEPOINT must be a 32-byte BINARY! for curve25519}",
    assert(opt_basepoint ? basepoint_size == 32 : basepoint_size == 0);

    REBYTE mypublic[32];  // "public" is a C++ keyword :-/

    curve25519(mypublic, secret, opt_basepoint);
    rebFree(opt_basepoint);  // null-tolerant, like C's free()

    return rebSizedBinary(mypublic, 32);

Here you see the power of libRebol's hybridized calls. rebBytes isn't just a routine for extracting the binary bytes out of a Rebol value...it's able to do a size check first (which FAILs if it needs to). Then the last item in the evaluation is the argument itself. C's 0-for-null is leveraged simply, so that if an argument is null the extractors just give back null.

Being able to do this in plain ANSI C is really rather awesome!

1 Like