Thread overview
array and pointers
Jan 25, 2007
Alberto
Jan 25, 2007
Matthew Wesley
Jan 25, 2007
Frits van Bommel
Jan 25, 2007
Frits van Bommel
January 25, 2007
hi, I have just started to play with D, and I have some little problem.

In C I did something like:

#define uchar  unsigned char

void aes_ecb_decrypt(aes_context *ctx, uchar *input, uchar *output, uint
len ) {
    int n;
    uchar *pin, *pout;

    // test to validate parameters..

    n = len;
    pin = input;
    pout = output;

    while( n > 0 ) {
        decrypt_block(ctx, pin, pout );
        pin  += 16;
        pout += 16;
        n -= 16;
    }
}

in D:

void decrypt_block(ubyte[] input, ubyte[] output) ;

ubyte[] ecb_decrypt(in ubyte[] input)
	in {
		assert(input.length > 0);
	}
	out(output) {
		assert(output.length == input.length);
	}
	body {
		int i,n, idx;
		ubyte[] pin;
		ubyte[] pout;
		ubyte[] output;

		n = input.length;
		output.length = n;
		idx=0;

		while( n > 0 ) {
			if (idx+BLOCK_SIZE >= input.length) {
				//we must decrypt less then BLOCK_SIZE
				decrypt_block(input[idx..$], output[idx..$]);
			} else {
				decrypt_block( input[idx..idx+BLOCK_SIZE], output[idx..idx+BLOCK_SIZE]);
			}
			idx += BLOCK_SIZE;
			n -= BLOCK_SIZE;
		}
		return output;
	}

but I don't think that is the right way..
There is a simpler way using pointers like in C?
I have tried to use something like:


	int n;
	ubyte *pin;
	ubyte *pout;
	ubyte[] output;

	n = input.length;
	output.length = n;
	pin = input.ptr;
	pout = output.ptr;

	while( n > 0 ) {
		decrypt_block(cast(ubyte[])pin, cast(ubyte[])pout);
		pin  += 16;
		pout += 16;
		n -= 16;
	}

but I get:
test_aes.d(158): Error: e2ir: cannot cast from ubyte* to ubyte[]
test_aes.d(158): Error: e2ir: cannot cast from ubyte* to ubyte[]

yes I can modify decrypt_block, but this is not the point, I want just understand how can I solve it, in a D way.


January 25, 2007
On Thu, 25 Jan 2007 12:36:53 +0100
Alberto <reda@zioale.it> wrote:

> hi, I have just started to play with D, and I have some little problem.
> 
> In C I did something like:
> 
> #define uchar  unsigned char
> 
> void aes_ecb_decrypt(aes_context *ctx, uchar *input, uchar *output,
> uint len ) {
>     int n;
>     uchar *pin, *pout;
> 
>     // test to validate parameters..
> 
>     n = len;
>     pin = input;
>     pout = output;
> 
>     while( n > 0 ) {
>         decrypt_block(ctx, pin, pout );
>         pin  += 16;
>         pout += 16;
>         n -= 16;
>     }
> }
> 
> in D:
> 
> void decrypt_block(ubyte[] input, ubyte[] output) ;
> 
> ubyte[] ecb_decrypt(in ubyte[] input)
> 	in {
> 		assert(input.length > 0);
> 	}
> 	out(output) {
> 		assert(output.length == input.length);
> 	}
> 	body {
> 		int i,n, idx;
> 		ubyte[] pin;
> 		ubyte[] pout;
> 		ubyte[] output;
> 
> 		n = input.length;
> 		output.length = n;
> 		idx=0;
> 
> 		while( n > 0 ) {
> 			if (idx+BLOCK_SIZE >= input.length) {
> 				//we must decrypt less then BLOCK_SIZE
> 				decrypt_block(input[idx..$],
> output[idx..$]); } else {
> 				decrypt_block( input[idx..idx+BLOCK_SIZE],
> output[idx..idx+BLOCK_SIZE]); }
> 			idx += BLOCK_SIZE;
> 			n -= BLOCK_SIZE;
> 		}
> 		return output;
> 	}
> 
> but I don't think that is the right way..
> There is a simpler way using pointers like in C?
> I have tried to use something like:
> 
> 
> 	int n;
> 	ubyte *pin;
> 	ubyte *pout;
> 	ubyte[] output;
> 
> 	n = input.length;
> 	output.length = n;
> 	pin = input.ptr;
> 	pout = output.ptr;
> 
> 	while( n > 0 ) {
> 		decrypt_block(cast(ubyte[])pin, cast(ubyte[])pout);
> 		pin  += 16;
> 		pout += 16;
> 		n -= 16;
> 	}
> 
> but I get:
> test_aes.d(158): Error: e2ir: cannot cast from ubyte* to ubyte[]
> test_aes.d(158): Error: e2ir: cannot cast from ubyte* to ubyte[]
> 
> yes I can modify decrypt_block, but this is not the point, I want just understand how can I solve it, in a D way.
> 
> 

The problem you are having is that arrays in D are not like arrays in C. Think of D arrays as:

struct DArray {
	type *ptr;
	size_t length;
}

This means there is no way to cast from a pointer to a D array, because D MUST know the length of that array.

Here is my solution to the same ECB problem:

void[] encrypt_ECB(void[] data, void[]to)
in {
    assert(data.length > 0);
    assert(to is null || to.length >= data.length + pad_length(data));
} out(ciphertext) {
    assert(ciphertext.length >= data.length);
    assert(ciphertext.length <= data.length +b_size);
    assert(ciphertext.length % b_size == 0);
 body {
    ubyte pad = pad_length(data);
    size_t total = data.length + pad;
    if(to is null)
          to = new ubyte[total];

     // copy and pad data
     to[0 .. data.length] = data;
     to[data.length .. total] = pad;
     assert(to.length % b_size == 0);

     for(size_t i=0; i < data.length; i += b_size) {
            encipher(output[i .. i+b_size]);
     }

     return to;
}

This is a member function of my BlockCipherAlg abstract class. Sub-classes of BlockCipherAlg implement encipher(void[]), allowing me to write one ECB, CBC, PCBC and other chaining method implementations for all block algorithms. If you're interested, I have a nearly complete version of my crypto library framework.

-- 
-----------------------------------------------------
PGP public key ID:
pub   2048R/2C19B7E6 2006-02-19 [expires: 2007-02-19]
uid                  Matthew Wesley <mwesley@acm.org>
Find it at http://pgp.mit.edu
-----------------------------------------------------
January 25, 2007
Matthew Wesley wrote:
> Think of D arrays as:
> 
> struct DArray {
> 	type *ptr;
> 	size_t length;
> }

Nitpick: the members are the other way around :p. (in DMD)
Not that it usually matters, but this may come up when writing inline assembly or calling extern(C) functions.
This is not in the spec though, so it's implementation-dependent.
However, it's not likely to change in DMD until Walter finally gets sick of printf[1]...


[1]: The current layout allows him to write 'printf("%.*s", string);' to print D strings.
January 25, 2007
Frits van Bommel wrote:

> Nitpick: the members are the other way around :p. (in DMD)
> Not that it usually matters, but this may come up when writing inline assembly or calling extern(C) functions.
> This is not in the spec though, so it's implementation-dependent.

If you're going to nitpick, then it's implemented as a ulong
(32-bit length | 32-bit ptr) in DMD and as a struct in GDC...
This makes a difference for return values. Or when debugging.
And it definitely will later, when D supports 64-bit as well.

But most of the time, you can just use .length and .ptr :-)

--anders
January 25, 2007
Anders F Björklund wrote:
> Frits van Bommel wrote:
> 
>> Nitpick: the members are the other way around :p. (in DMD)
>> Not that it usually matters, but this may come up when writing inline assembly or calling extern(C) functions.
>> This is not in the spec though, so it's implementation-dependent.
> 
> If you're going to nitpick, then it's implemented as a ulong
> (32-bit length | 32-bit ptr) in DMD and as a struct in GDC...
> This makes a difference for return values. Or when debugging.
> And it definitely will later, when D supports 64-bit as well.
> 
> But most of the time, you can just use .length and .ptr :-)

Well, AFAIK the only real difference between ulongs and 8-byte structs is how they're returned from extern(C) functions (and perhaps extern(Windows/Pascal) as well).

The only reason I even *know* that is that several functions (e.g. _d_arrayappendT (previously _d_arrayappend) in Phobos) have their calling conventions all screwed up ;).
They get parameters passed like a C function, but return an array like a D function would.
This doesn't actually matter to the typical user, since they're only called internally by compiler-generated code that expects exactly that.
So for every-day use, I'd say the struct is way easier to understand and correct enough :p.