Sample code for 30+ languages & platforms
Zig

ECDSA Sign Data and Get Raw R and S Values

See more ECC Examples

Demonstrates getting the raw R and S value of an ECDSA signature.

Chilkat Zig Downloads

Zig
const std = @import("std");
const chilkat = @import("chilkat");

pub fn main(init: std.process.Init) !void {
    const alloc = init.arena.allocator();

    // This example requires the Chilkat API to have been previously unlocked.
    // See Global Unlock Sample for sample code.

    // To create an ECDSA signature, the data first needs to be hashed.  Then the hash
    // is signed.

    const crypt = try chilkat.Crypt2.init();
    defer crypt.deinit();
    crypt.setHashAlgorithm("SHA256");
    crypt.setCharset("utf-8");
    crypt.setEncodingMode("base64");

    // Hash a string.
    const hash1 = try crypt.hashStringENC(alloc, "The quick brown fox jumps over the lazy dog");
    std.debug.print("hash1 = {s}\n", .{hash1});

    // -----------------------------------------------------------
    // An ECDSA private key is used for signing.  The public key is for signature verification.
    // Load our ECC private key.
    // Our private key file contains this:

    //     // -----BEGIN PRIVATE KEY-----
    //     MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg3J8q/24D1sEKGdP9
    //     72MGYElLGpw/a56Y3t6pfON3uhShRANCAATlSmoizyhAwoYZAOuFBATl07/1RR54
    //     a1Dzfm16grxJe666AGKR+bSs24hk7TEpaeCTvT8YOOM3l+xKFg7zq6Q9
    //     -----END PRIVATE KEY-----

    const priv_key = try chilkat.PrivateKey.init();
    defer priv_key.deinit();
    priv_key.loadPemFile("qa_data/ecc/secp256r1-key-pkcs8.pem") catch {
        std.debug.print("{s}\n", .{try priv_key.getLastErrorText(alloc)});
        return;
    };

    // Sign the hash..
    const prng = try chilkat.Prng.init();
    defer prng.deinit();
    const ecdsa = try chilkat.Ecc.init();
    defer ecdsa.deinit();
    const ecdsa_sig_base64 = ecdsa.signHashENC(alloc, hash1, "base64", priv_key, prng) catch {
        std.debug.print("{s}\n", .{try ecdsa.getLastErrorText(alloc)});
        return;
    };

    // The ECDSA signature is ASN.1 that contains a sequence of 2 large integers (r and s)
    // For example:
    // SEQUENCE (2 elem)
    //   INTEGER (255 bit) 792134D9B4AD82D5431ED03835A88E2596EB35E5B13054BD9B05A0069281ACC9
    //   INTEGER (255 bit) 481E758CC1E3CBF825537EC3D9A2CA627E5FAD1137BBEA65DF38658DCB0A9ED5

    std.debug.print("Base64 ECDSA signature = {s}\n", .{ecdsa_sig_base64});

    // If the raw R and S values are needed, here's how to get them:
    const asn = try chilkat.Asn.init();
    defer asn.deinit();
    asn.loadEncoded(ecdsa_sig_base64, "base64") catch {
        std.debug.print("{s}\n", .{try asn.getLastErrorText(alloc)});
        return;
    };

    // The R and X will be in hexidecimal in the XML.
    const xml = try chilkat.Xml.init();
    defer xml.deinit();
    xml.loadXml(try asn.asnToXml(alloc)) catch {};
    std.debug.print("{s}\n", .{try xml.getXml(alloc)});

    // The XML looks like this:
    // <sequence>
    // <int>792134D9B4AD82D5431ED03835A88E2596EB35E5B13054BD9B05A0069281ACC9</int>
    // <int>481E758CC1E3CBF825537EC3D9A2CA627E5FAD1137BBEA65DF38658DCB0A9ED5</int>
    // </sequence>

    // Copy raw R and S hex values into a Chilkat BinData object.
    const bd = try chilkat.BinData.init();
    defer bd.deinit();
    const r = try xml.getChildContent(alloc, "int[0]");
    const s = try xml.getChildContent(alloc, "int[1]");
    bd.appendEncoded(r, "hex") catch {};
    bd.appendEncoded(s, "hex") catch {};

    std.debug.print("Number of bytes in bd: {d}\n", .{bd.getNumBytes()});
}